Programming

Fix TF_SessionPRun 'Must Run Setup' Error TensorFlow C API

Resolve TensorFlow C API TF_SessionPRun errors: 'Local rendezvous CANCELLED PRun cancellation' and 'Must run setup before partial runs'. Checklist, code patterns, Windows MinGW tips for efficient streaming inference with Keras SavedModel.

1 answer 1 view

TensorFlow C API: TF_SessionPRun() shows ‘Local rendezvous is aborting with status: CANCELLED: PRun cancellation’ on first call and fails subsequent calls with ‘Must run 'setup' before performing partial runs!’

I am using TF_SessionPRun() from the TensorFlow C API (version 2.18.1 on Windows with MinGW GCC 8.1.0) to perform consecutive calculations on streaming data from a Keras SavedModel with 6 inputs and 2 outputs.

Expected Usage

TF_SessionPRunSetup(session, input_op_list, input_tensor_list, output_op_list, output_tensor_list, target_op_list, &handle); // Get handle
while (some condition) {
 TF_SessionPRun(session, handle, input_op_list, input_tensor_list, Ninputs, output_op_list, output_tensor_list, Noutputs, target_op_list, Ntargets, NULL);
}
TF_DeletePRunHandle(handle);

Issue

  • The first TF_SessionPRun() returns TF_OK with correct outputs, but logs:
I tensorflow/core/framework/local_rendezvous.cc:405] Local rendezvous is aborting with status: CANCELLED: PRun cancellation
  • Subsequent TF_SessionPRun() calls fail with:
Must run 'setup' before performing partial runs!

Sample Output (First PRun succeeds, second fails)

TF_SessionPRunSetup is OK. handle=000000000401C500
Calling TF_SessionPRun().
2026-01-12 14:12:14.925789: I tensorflow/core/framework/local_rendezvous.cc:405] Local rendezvous is aborting with status: CANCELLED: PRun cancellation
TF_SessionPRun is OK. Took 59613218 cycles.
OUTPUT[00]: 2.246543 -59.455326
... (other outputs)
Calling TF_SessionPRun().
Must run 'setup' before performing partial runs!

Comparison with TF_SessionRun()

Using TF_SessionRun() for each iteration works but is slower (higher clock cycles on first run, then faster):

TF_SessionRun is OK. Took 97826776 cycles. // First
TF_SessionRun is OK. Took 442369 cycles. // Subsequent
...

How can I correctly use TF_SessionPRun() for efficient consecutive partial runs without these errors?

The first “Local rendezvous … PRun cancellation” message is informational; TF_SessionPRun can still return TF_OK on that call. The later “Must run ‘setup’ before performing partial runs!” means the partial-run handle created by TF_SessionPRunSetup was not valid for the next call (setup failed or the handle/session was invalidated). Verify TF_SessionPRunSetup returned TF_OK and a non‑NULL handle, keep and reuse that handle (don’t delete the handle or close the session between iterations), make sure your feed/fetch arrays and counts match the setup, and run the official C API test pattern to reproduce and debug.


Contents


TF_SessionPRun and TF_SessionPRunSetup (TensorFlow C API)

TF_SessionPRunSetup creates an opaque handle used to perform multiple partial runs with TF_SessionPRun; you call setup once, then TF_SessionPRun repeatedly, and finally TF_DeletePRunHandle when you’re done. The authoritative C header and the test-suite show this pattern and emphasize checking the setup status and preserving the handle across runs. See the official header for details and the test that demonstrates the pattern: tensorflow/c/c_api.h and tensorflow/c/c_api_test.cc.

A few important behavioral points (from the header/tests):

  • The handle returned by TF_SessionPRunSetup is an opaque string; don’t modify it and don’t free it yourself.
  • TF_SessionPRun may log “Local rendezvous is aborting with status: CANCELLED: PRun cancellation” on a fast/terminal partial run even when it returns TF_OK — that log can be informational, not an error.
  • If later TF_SessionPRun calls fail with “Must run ‘setup’ before performing partial runs!”, the runtime believes the handle wasn’t created, has been deleted, or the session was closed.

So: the first PRun logging that message is not by itself the cause of the failure — the failure means the handle or session state became invalid before your second call.


Why you see “PRun cancellation” and “Must run ‘setup’…”

What’s happening under the hood? The “Local rendezvous … PRun cancellation” message comes from TensorFlow’s rendezvous layer when a partial-run execution ends or an internal operation cancels outstanding receives; the C header and tests accept that this info log may appear even on TF_OK returns. The later “Must run ‘setup’…” occurs when the library no longer recognizes a valid partial-run handle.

Common root causes:

  • TF_SessionPRunSetup actually failed (status not checked) and the handle was never established.
  • The handle variable was overwritten, out of scope, or passed incorrectly to TF_SessionPRun (passing &handle vs handle by mistake).
  • TF_DeletePRunHandle (or session close/delete) was called too early.
  • The feed/fetch lists or counts you pass to TF_SessionPRun don’t match the superset you registered with TF_SessionPRunSetup (indexing/ordering mismatch).
  • Concurrency problems: the same handle used concurrently from multiple threads without synchronization.
  • Toolchain/ABI or memory-corruption issues (less common): mixing runtimes or incompatible builds could corrupt pointers.

The StackOverflow thread on partial_run errors highlights the usual case: a failed setup or mishandled handle is the typical culprit — make sure your setup succeeded and that you reuse the handle exactly as returned by setup (StackOverflow example). For more background on the C API oddities, see the community writeup on undocumented bits (Medium article).


Checklist: TF_SessionPRunSetup & TF_SessionPRun quick fixes

Run through these checks in order — they fix ~95% of cases like yours.

  1. Confirm TF_SessionPRunSetup returned TF_OK and handle != NULL
  • Always call TF_SessionPRunSetup with a TF_Status and inspect TF_GetCode(status) and TF_Message(status).
  • After setup print the handle pointer so you can watch it across iterations:
  • printf(“TF_SessionPRunSetup OK. handle=%p\n”, (void*)handle);
  1. Use the same handle (and type) in TF_SessionPRun
  • TF_SessionPRun expects the handle (const char*). Pass handle, not &handle.
  • Keep the handle variable in scope for the entire loop.
  1. Don’t delete the handle or close the session until you’re finished
  • Call TF_DeletePRunHandle(handle) only after the loop completes.
  • Don’t call TF_CloseSession/TF_DeleteSession between partial runs.
  1. Verify your feed/fetch arrays & counts
  • TF_SessionPRunSetup should receive the superset of all inputs/outputs you’ll ever use; TF_SessionPRun can then supply a subset each iteration.
  • Make sure Ninputs, Noutputs match the actual arrays you pass on each call and that their ordering/mapping matches the setup’s expectations.
  1. Keep input TF_Tensor objects valid until TF_SessionPRun returns
  • Create TF_Tensor for each input before the call, and delete it only after the run returns.
  • If you reuse buffers, confirm they’re not freed or overwritten earlier.
  1. Single-threaded use or proper locking
  • Either use the handle only on one thread, or protect TF_SessionPRun calls with a mutex for that handle.
  1. Print status messages every call
  • On each TF_SessionPRun call check TF_GetCode(status) and print TF_Message(status) — this often shows subtle setup failures.
  1. Reproduce with the official test
  • Try the official c_api_test.cc pattern. If that works but your code fails, the problem is in your setup/handle/lifecycle.

If any check fails, fix it and re-run. Most often one of (1), (2) or (3) is the actual mistake.


Minimal working pattern (copy-paste, with status checks)

The following skeleton follows the test pattern: one setup, many partial runs, then delete the handle.

c
/* Minimal PRun usage pattern (outline) */
TF_Status* status = TF_NewStatus();
char* handle = NULL;

/* 1) Setup: provide the superset of feeds/fetches */
TF_SessionPRunSetup(session,
 all_input_ops, (int)all_ninputs,
 all_output_ops, (int)all_noutputs,
 all_target_ops, (int)all_ntargets,
 &handle, status);
if (TF_GetCode(status) != TF_OK) {
 fprintf(stderr, "PRunSetup failed: %s\n", TF_Message(status));
 /* handle error and return */
}
printf("TF_SessionPRunSetup is OK. handle=%p\n", (void*)handle);

/* 2) Repeated partial runs using the same handle */
while (have_more_streaming_data()) {
 /* Build input_values array for this iteration (TF_Tensor*), set run_ninputs accordingly. */
 TF_SessionPRun(session, handle,
 run_input_ops, run_input_values, run_ninputs,
 run_output_ops, run_output_values, run_noutputs,
 run_target_ops, run_ntargets,
 status);
 if (TF_GetCode(status) != TF_OK) {
 fprintf(stderr, "PRun failed: %s\n", TF_Message(status));
 break;
 }
 /* consume outputs in run_output_values[] */
}

/* 3) Only after all partial runs complete: delete the handle */
TF_DeletePRunHandle(handle);
TF_DeleteStatus(status);

Notes:

  • Replace the arrays above with persistent TF_Output lists (the same ones you used in setup) or ensure the mapping/ordering is consistent.
  • If you see the informational “PRun cancellation” log on the first run but TF_GetCode(status) == TF_OK, that’s normal. The error comes when the handle becomes invalid.

See the official C API header and test for exact call signatures and a working example: c_api.h, c_api_test.cc.


Windows / MinGW and debugging tips

You said you’re using Windows + MinGW (GCC 8.1.0). A few platform-oriented checks:

  • Reproduce the simple c_api_test.cc example on your machine. If the test passes but your code fails, the issue is in your code; if the test fails too, it may be an environment/toolchain problem.
  • Mixing CRTs or incompatible runtimes can corrupt pointers/allocations. If you built/linked TensorFlow C library with a different compiler/CRT than MinGW, you may see pointer/handle corruption. Try using a TensorFlow C library built with the same toolchain or run the same code with MSVC or on Linux to isolate the problem.
  • Increase logging to capture more runtime messages. The informational log you posted is printed at INFO level; keep logs enabled while debugging.
  • If you suspect ABI or memory corruption, run the code under Valgrind on Linux (or use ASAN builds if available) to catch misuse of pointers or double frees.

If you cannot fix it quickly on this toolchain, try a simple MSVC build or test on Linux to verify the PRun pattern itself works on your model and workflow.


If PRun still fails: fallbacks and performance tips

If you can’t stabilize TF_SessionPRun on your platform, you have options:

  • Fallback to TF_SessionRun each iteration (you already measured it works). It’s slower because the runtime re-prepares execution state, but it’s reliable.
  • Reduce TF_SessionRun overhead: reuse and pre-allocate TF_Tensor buffers, avoid reloading graph each iteration, and keep the session open — that narrows the gap.
  • Batch streaming inputs so you call TF_SessionRun less frequently.
  • Re-evaluate approach: for high-throughput streaming inference, consider serving models with TensorFlow Serving or a dedicated inference API which keeps runner state for you.

Performance note: TF_SessionRun shows a heavy first-run cost (graph/execution plan preparation) and then much faster subsequent runs. TF_SessionPRun aims to eliminate that first-run overhead by reusing setup; that’s why getting handle/PRun to work is worth the effort if you need many tiny iterations.


Sources


Conclusion

In short: the “PRun cancellation” info log is usually benign, but the later “Must run ‘setup’…” means your partial-run handle or session state is invalid. Check TF_SessionPRunSetup’s TF_Status and handle, keep and reuse that handle (don’t delete it or close the session until all PRuns finish), ensure feed/fetch arrays and counts match the setup, and reproduce the official test to rule out toolchain issues. Fixing one of those lifecycle or mapping problems will let you use TF_SessionPRun in the TensorFlow C API for efficient consecutive partial runs.

Authors
Verified by moderation
Moderation
Fix TF_SessionPRun 'Must Run Setup' Error TensorFlow C API