Troubleshooting and FAQ

Find the error code or the symptom below. Every CriogenAI error has a stable code (error.code); the full catalog is on Error codes, and how to catch errors is on Errors and retries.

Install#

Which version do I have?#

python -c "import criogenai; print(criogenai.__version__)"
npm ls criogenai criogenai-windows-x64

Linux or macOS: no engine, or a feature is missing#

The packages were renamed from criogen to criogenai in 0.1.7, and the new name does not yet have engines for every platform:

Platformcriogenai (Python / Node.js)Until then: old criogen
Windows x640.1.7 / 0.1.7–
Linux x64, Linux ARM64, macOS Apple Siliconfrom 16 November0.1.3 engine
macOS Intelfrom 16 NovemberPython 0.1.2, Node.js engine 0.1.3
Browser (criogenai/web)– / 0.1.7–

On Linux and macOS until then, install criogen and import criogen; switch the install and the imports to criogenai once its engines are out. Features marked 0.1.4 or later on the status page (MCP, collections, evals, the trace viewer, Azure, Bedrock, Vertex AI, the Responses API, FunctionModel) are not in a 0.1.3 engine; in TypeScript they fail with unsupported and say which engine they need.

native_unavailable (TypeScript) or no wheel found (Python)#

The package has no engine for this system. Supported: Linux x64 and ARM64 with glibc 2.28 or newer, macOS (Apple Silicon and Intel), Windows x64. Not supported yet: Alpine and other musl-based Linux, Windows on ARM, 32-bit systems, and Edge runtimes.

  • TypeScript: importing criogenai never fails; the first use throws NativeUnavailableError with details.platform, details.arch, details.libc and the package it tried. If the platform is supported, the engine package was probably not installed: npm skips it when optional dependencies are turned off (--omit=optional, --no-optional) or when the lock file was made on another platform. Reinstall without those flags, or add the platform package (criogenai-linux-x64, ...) explicitly.
  • Python: pip says "no matching distribution" on an unsupported platform or Python older than 3.9. Check python --version and the platform.
  • Docker: use a Debian- or Ubuntu-based image, not Alpine.

pip prints retry warnings for another index#

If your pip configuration has an extra index that cannot be reached, pip prints warnings and then installs from PyPI. The warnings are harmless; remove the extra index from your pip configuration to silence them.

Keys#

"invalid_value: no API key for openai: set OPENAI_API_KEY ..."#

Building an agent with a hosted model checks for its key at once, and fails with a ValidationError (code invalid_value; in Python also a ValueError) naming the variable (ready(model) reports the same text in its model.error instead of raising). Set it in the environment, or put it in a .env file and call load_env() / loadEnv() before you build the agent. Each provider has its own variable (Models). Self-hosted models (ollama:, lmstudio:) need none.

model_failed with kind auth or permission#

The provider refused the key, or the key may not use this model. Check that the variable holds the right key for this provider (an OpenAI key does not work for gemini:), that it has not expired, and that the account has access to the model. Keys never appear in errors or logs, so the message will not show which key was sent: print criogenai.env.status() (Python) or envStatus() (TypeScript) to see which providers have a key set (names and yes/no only).

model_failed with kind not_found#

The provider does not know the model name. Check its spelling against the provider's model list (openai:gpt-5-mini, not gpt-5-mini alone, and no spaces).

Errors by code#

CodeUsually meansWhat to do
thread_busyAnother call is running on this thread (a double click, two tabs), and the wait timed out or storage rejectsWait, or tell the user; see on_busy in Storage
thread_suspendedAn approval waits on this threadapprove(), reject() or decide() first (Approval)
thread_interruptedThe process died while the last run was goingretry() continues it
resume_invalidretry() with nothing to retry; approve() with nothing waiting; a decision for an unknown call, or missing oneCheck history(); answer every waiting call
workflow_mismatchA paused or saved run is continued by an agent or workflow built differently (for example, without the approve list it paused with)Continue it with the same configuration, then change it
limit_exceededModel calls, tool calls, tokens or nesting ran out (details["limit"])Raise the limit, or fix what loops (often a tool that keeps failing)
model_failedThe model failed after retries and fallbacks (details["model_error"]["kind"])Transient kinds: retry later or add fallbacks. context_overflow: shorten the thread or fall back to a longer-context model
output_invalidTyped output still invalid after 2 correctionsSimplify the schema; describe each field; check details["raw"]
tool_failedA tool crashed and on_tool_exception is "fail"The exception is the error's cause (__cause__ / cause)
hook_failedA hook raisedThe exception is the error's cause
invalid_stateMemory by state, but the run has no value for its keyPass it: send(text, user_id=...)
invalid_inputA message sets one of the agent's own state keys, or changes the memory key of a threadUse another key name; keep the same user per thread
invalid_workflowThe graph does not validate (details["issues"] lists every problem)Fix each issue listed
update_conflictTwo parallel nodes wrote the same key in one stepGive the key a reducer (append), or write different keys
node_failedA workflow node raisedThe exception is the error's cause; retry() on a thread
step_limit_exceeded, deadline_exceededA workflow loop did not end in timeCheck the loop's exit, or raise max_steps / deadline
cancelledA signal fired, the task was cancelled, a stream was left, or on_busy="interrupt" replaced the callretry() continues it on a thread
storage_unavailableThe database cannot be reached, timed out, or close() was calledCheck the URL and network; do not use a storage after closing it
storage_incompatibleThe database was written by a newer CriogenAIUpgrade the package
encryption_key_missing, encryption_key_invalidAn encrypted database opened without (or with the wrong) keysPass the same encryption_keys as before (Encryption)
audit_failedThe audit trail is on and a record could not be written, so the action did not happenCheck the database; the action can be retried
unsupportedThe feature needs a server (in criogenai/web), or a newer engine than the one installedSee the install table above
native_unavailableNo engine for this systemSee above

Tool problems#

The model calls a tool with the wrong arguments again and again. Each time it sees invalid_arguments with the problems. Make the schema and description clearer (an example value helps: "an id like A-1001"), and keep argument names plain. The model-call limit ends a loop that does not converge.

A tool's exception text reaches the model. That is the default (on_tool_exception="return_to_model"). Use "return_generic" to hide it, or raise ToolError with a message written for the model.

A tool times out. The default limit is 60 s per call. Raise it with limits={"tool_timeout_secs": 120} (limits: { toolTimeoutSecs: 120 }), or make the tool return quickly (start the long job, return a reference, and add a second tool to check on it).

A tool ran twice. Within one run, only read_only and idempotent tools are retried. After a crash, retry() does not repeat tool calls that had finished, but a call that was in progress when the process died may run again. Use the call id (ctx.call_id) as an idempotency key for anything that sends or pays.

Timeouts and slow runs#

  • Model calls have the provider's own time limits; a timeout is a transient error and is retried. To bound a whole call, use a signal (TypeScript: { signal: AbortSignal.timeout(30_000) }) or asyncio.wait_for(...) (Python).
  • Runs that take many model calls are usually loops: look at result.messages (or the trace viewer) to see what the model kept trying.
  • Workflows take max_steps and deadline.

Python#

RuntimeError: the *_sync methods cannot run inside an event loop. run_sync and send_sync are for scripts. In async code (FastAPI, Jupyter notebooks, which run an event loop), await agent.run(...) instead.

asyncio.CancelledError versus criogenai.CancelledError. Cancelling your own task raises asyncio's. CriogenAI's (code cancelled) means the run was cancelled for another reason, such as a stream you left.

TypeError: no JSON Schema for the type ... when defining a tool. The parameter's type hint has no JSON form. Use str, int, float, bool, list, dict, Literal, Optional or a Pydantic model.

TypeScript and Next.js#

await at the top level fails. Use ES modules: "type": "module" in package.json, or .mts files.

Next.js fails to bundle criogenai, or the route says the engine is unavailable. Add serverExternalPackages: ["criogenai"] to next.config.mjs and export const runtime = "nodejs" to the route. The Edge runtime cannot load native code (Deploying).

FAQ#

Does CriogenAI send my data anywhere? Only to the model providers you configure, and to a tracing endpoint if you set one. Tracing exports no message content unless you turn content capture on. There is no usage reporting from the package.

Can it run without any cloud provider? Yes: use a self-hosted model (ollama:, lmstudio:, or OpenAICompatible for vLLM and other servers) and SQLite or Postgres on your own machines. Embedder.ollama(...) keeps memory search local too.

How do I see what an agent did? result.messages has the whole transcript, including every tool call and result. For a timeline of every run, use the local trace viewer or Langfuse (Tracing).

Can two users share a thread? Yes: a thread is just an id. Give each person their own handle with their actor, and runs take turns.

Can I change the tools of an agent with existing threads? Yes, between turns: the thread stores the conversation, not the tools, and send and retry work with the new agent. Calls to a tool that no longer exists come back as unknown_tool. A run that is waiting for approval must be answered by an agent with the same tools and approve list as the one that paused it; otherwise the answer fails with workflow_mismatch or resume_invalid. Answer waiting approvals before you deploy such a change.

How do I delete everything about a person? Delete their threads (thread.delete()) and their memory (forget_all("users/<id>")). See Long-term memory.

Is the source code available? Not yet. The Python and TypeScript packages are free to use; the code opens when the packages reach 10,000 installs. The Rust crates are published then too.

Still stuck#

Check Status: built and planned to see if what you need exists yet, and the API reference for exact signatures.