Skip to Content
Known Issues

Known Issues

Everything here is real, reproduced, and open against v3.0.0. It is published rather than quietly tracked because most of these fail silently — you get a plausible wrong answer, not an error — and an hour spent debugging one of them is an hour this page could have saved.

The worst kind first: a tool that raises still completes the run successfully. If you are debugging an agent that seems to ignore its tools, read that entry before anything else.

Silent wrong answers

These produce no error. Nothing in the log says anything went wrong.

A tool that raises completes the run

An exception inside a tool produces no machine-readable signal at any layer. The run completes, the caller gets a normal result, HTTP answers 200, and tool.call.completed.error is never set. The only trace is that the model saw an error string and may or may not have mentioned it.

Until it is fixed: catch exceptions inside your own tools and return a string the model can act on. Do not rely on the run failing.  → #250 

A tool returning something unserializable reaches the model as a memory address

Return a value JSON cannot carry and it is neither rejected nor flagged — it is coerced to its repr(), and that string, typically containing a raw memory address, enters both the event log and the prompt.

Until it is fixed: return JSON-compatible values from tools. If you return an object today, check what the model is actually receiving.  → #251, folded into #250 

Agent(model=...) is ignored

Every run uses OPENAI_MODEL, whatever the agent declared. The parameter is accepted, type-checked by the SDK, and then overridden by the run’s own configuration — so a cheap router in front of an expensive specialist silently runs entirely on one model.

Until it is fixed: there is no per-agent model. One model per process.  → #247 

Cancelling a run that is waiting on a human does nothing

deck.cancel(run_id) against a run parked at interrupt() returns True and records the signal. Nothing reads it. The run stays answerable, and answering it executes the rest of the workflow for real. No event is written, so the log shows no trace that a cancel was asked for.

Until it is fixed: do not rely on cancel to stop a pending approval. Guard the post-approval nodes with your own check.  → #229 

usage.usd is always None

The cost field exists on every Usage and never carries a cost.

Until it is fixed: compute cost from input_tokens/output_tokens and your own price table.  → #177 

Defaults that will trap you

A default install cannot run a durable workflow

AGENTDECK_CHECKPOINT defaults to sqlite://.agentdeck/checkpoints.sqlite3, but the SQLite checkpointer lives behind the [durability] extra. So durable = True — which every human approval needs — fails on a plain install.

Until it is fixed: install agentdeck[durability] if you use durable = True.  → #232 

Approvals disappear on restart, under the shipped defaults

AGENTDECK_EVENTS defaults to memory:// while AGENTDECK_CHECKPOINT defaults to durable SQLite. deck.pending() reads the event log; the timer path reads the checkpointer. After a restart the two disagree, and a parked approval can never be answered because pending() returns an empty list.

Until it is fixed: set AGENTDECK_EVENTS to a durable store — sqlite://, postgresql:// or redis:// — in anything that outlives one process. See Choosing a Store Backend.  → #212 

A killed worker holds its session for an hour

A worker killed mid-turn leaves its session_id unusable for AGENTDECK_RUNTIME_STALE_RUN_AFTER_SECONDS, which defaults to 3600. There is no way to release it sooner.

Until it is fixed: lower the setting if your deployment restarts often. It trades against how long a healthy turn may go quiet.  → #244 

Provider compatibility

Handoffs fail against non-OpenAI endpoints

Against an OpenAI-compatible endpoint that is not OpenAI, a handoff returns a bare 400. On Gemini’s endpoint the message is:

400 - Please ensure that single turn requests end with a user role or the role field is empty.

A transfer produces an assistant tool-call followed by a tool result, so the transferred-to agent’s request ends on a non-user role, which some providers reject. The handoff mechanism itself is fine — a bidirectional round trip works against a compliant endpoint.

Until it is fixed: run handoffs against OpenAI. Pointing one agent at a different provider is not a workaround — see Agent(model=...) above.  → #178 

Rough edges

Not silent, not traps — just things that will cost you a few minutes.

WhatIssue
agentdeck-serve --help crashes instead of printing usage#245 
run()’s return type makes the documented interrupt idiom fail a type checker#231 
Checkpointer connection failures surface as raw driver exceptions, not StoreError#233 
An engine failure over HTTP returns bare text rather than the documented 500 shape#243 
answer() accepts any value with no validation, and the node owns interpreting it#235 
Omitting context on answer() silently gives the re-run node None#255 
The CLI can send signals but cannot read anything — no inbox, no run view#256 
redis is a base dependency because the default session path imports it#253 
A DataBlock cannot be sent to a model, only received from one#226 
Deck.asgi() cannot serve an agent whose tools declare a Context#227 

What is being done about all this

Every entry above is on v3.1 — hardening, which exists for exactly this list. See the Roadmap.

Hit something that is not here? Open an issue . A reproduction is worth more than a diagnosis — most of this page came from people who sent one.

Last updated on