Summary
When several minimax-code processes run in parallel (common for power users running multiple sessions), turns intermittently die with:
The response failed.
Reason: database is locked
The failure is local, not an upstream API error — the request never reaches the network. From ~/.minimax/v2/observability/logs/runtime-*.log:
[pi-turn-runner] history delivery failed ... SqliteError: database is locked
at sqliteTransaction (.../better-sqlite3/lib/methods/transaction.js:63:9)
[local-runtime-v2] agent host turn failed ... failure_stage="Agent execution failed."
Root cause
All processes share a single ~/.minimax/v2/sqlite/runtime-state.sqlite (WAL mode). The runtime sets PRAGMA busy_timeout = 5000, but under N concurrent writers a 5s wait is not always enough, and no retry on SQLITE_BUSY exists — the transaction wrapper ($t, YMe, and the goal-repo transaction(r).immediate() call sites in the bundled chunks) throws immediately once the timeout expires. The turn then fails at history delivery / event writer stage and the whole agent turn is aborted.
Observed with 9 concurrent processes on a ~330 MB database; frequency grows with parallelism and DB size.
Suggested fixes (any of)
- Retry with backoff on
SQLITE_BUSY around the transaction helpers — cheapest, survives arbitrarily long foreign transactions.
- Raise
busy_timeout (e.g. 30s) — helps but does not cover BUSY_SNAPSHOT cases.
- Shard session-scoped tables per session (e.g.
runtime-state-<session>.sqlite) while keeping shared tables (local_runtime_agents, local_runtime_communication_messages, local_runtime_queues, local_runtime_crons, local_runtime_background_tasks, local_runtime_session_locks) in a coordinator DB — removes write contention entirely for the hot path. Note: a naive per-session split is not possible because the schema intentionally mixes session-scoped and cross-session coordination tables.
Environment
@minimax-ai/code 0.5.0 (npm), Linux x64, Node v24.18.0
- Repro: run 5+
mcode sessions concurrently with active tool calls; within an hour at least one turn dies with database is locked.
Summary
When several
minimax-codeprocesses run in parallel (common for power users running multiple sessions), turns intermittently die with:The failure is local, not an upstream API error — the request never reaches the network. From
~/.minimax/v2/observability/logs/runtime-*.log:Root cause
All processes share a single
~/.minimax/v2/sqlite/runtime-state.sqlite(WAL mode). The runtime setsPRAGMA busy_timeout = 5000, but under N concurrent writers a 5s wait is not always enough, and no retry on SQLITE_BUSY exists — the transaction wrapper ($t,YMe, and the goal-repotransaction(r).immediate()call sites in the bundled chunks) throws immediately once the timeout expires. The turn then fails athistory delivery/event writerstage and the whole agent turn is aborted.Observed with 9 concurrent processes on a ~330 MB database; frequency grows with parallelism and DB size.
Suggested fixes (any of)
SQLITE_BUSYaround the transaction helpers — cheapest, survives arbitrarily long foreign transactions.busy_timeout(e.g. 30s) — helps but does not coverBUSY_SNAPSHOTcases.runtime-state-<session>.sqlite) while keeping shared tables (local_runtime_agents,local_runtime_communication_messages,local_runtime_queues,local_runtime_crons,local_runtime_background_tasks,local_runtime_session_locks) in a coordinator DB — removes write contention entirely for the hot path. Note: a naive per-session split is not possible because the schema intentionally mixes session-scoped and cross-session coordination tables.Environment
@minimax-ai/code0.5.0 (npm), Linux x64, Node v24.18.0mcodesessions concurrently with active tool calls; within an hour at least one turn dies withdatabase is locked.