Troubleshooting¶
call invoke reports unavailable / "no eligible provider"¶
{"ok":false,"status":"unavailable","error":{"code":"unavailable","message":"no eligible provider"}}
exit code 7. This means exactly what it says: no connected provider has
registered that service.method. It is the correct response whether the
provider process hasn't started yet, already exited, or registered under
a different service/method name than you invoked. It is not a
configuration error — config validate on the same file will still
succeed, because declaring a method in the Polycallfile only makes it
invocable in principle (see
Core concepts).
Checklist:
- Is the provider process actually still running? (Check its terminal — a crashed provider leaves no trace in the runtime's own output.)
- Does the provider's
REGISTERmessage name match the Polycallfile exactly — sameservice, same method name? - Did the provider connect to the same
runtime.listenaddress the CLI's Polycallfile points at? Two different Polycallfiles with different ports will silently never see each other.
Authentication failures¶
The runtime and every provider (including provider.py and
math_provider.c) must resolve the same credential:
security.mode = "token"— both sides needtoken_envpointing at the same environment variable, set to the same value, in their respective process environments.security.mode = "local-auto"— both sides must run as the same OS user, since the credential lives in that user's Windows Credential Manager entry or~/.polycall-credentials/<runtime name>file. A provider run as a different user (or, on a shared machine, a stale credential from a previousruntime.name) will failAUTH— the provider printsprovider: authentication failed: ...and exits nonzero rather than retrying silently.
If you changed [runtime].name in the Polycallfile, any previously
stored local-auto credential is keyed to the old name and won't match;
restart the runtime so it (re)generates the credential for the current
name.
Port / listener conflicts¶
runtime start binding a port already in use fails at startup, before
printing runtime ready, listening. If a previous run's process is still
alive (see the shutdown section below), stop it first rather than
changing the port purely to work around a stuck process — a changed port
also requires updating any provider's Polycallfile to match, since the
listen address is read from the same file.
Malformed request files¶
call invoke --input request.json expects a JSON object with a single
args array of tagged values:
{"args":[{"type":"i64","value":"2"},{"type":"i64","value":"3"}]}
A missing type, a value that doesn't parse for its declared type, an
argument count that doesn't match the method's declared params, or a
type the method doesn't declare are all rejected — with math.add
specifically, sending fewer or more than two arguments, a non-i64 type,
or an out-of-range value all return a structured INVALID_ARGUMENT or
provider_error from the provider's own validation (see
Your first Python call),
not a crash.
Loader / linking errors for a C consumer¶
If a consumer built against -Llib -lpolycall fails to run (not
compile) with a missing-library error, that's the dynamic loader failing
to find libpolycall.so/.dll at run time — a completely separate
concern from the -L/-l link-time flags. See
C library and ABI: the default
build links the CLI statically precisely to avoid this class of problem;
if you're linking dynamically, place the shared library beside your
consumer or set an explicit loader path. Don't copy an unrelated
downloaded DLL into a system directory to make the error go away.
Shutdown seems to hang¶
If polycall runtime stop or Ctrl+C doesn't return quickly on a build
older than this session's fix, that's the Linux accept()/recv()
shutdown bug described in
Your first Python call —
rebuild from current main, which fixes it. On any build, remember
option placement rules apply to
runtime stop too: polycall runtime stop --json ./Polycallfile works,
polycall runtime stop ./Polycallfile --json is a usage error (exit 2)
and never reaches the runtime at all — that's a parsing rejection, not a
hang, but it looks similar if you're only watching for "did it print
something."