Before submitting
Area
apps/server
Steps to reproduce
- Run the server as a service (
t3 serve, headless deployment). - While the server is active, issue headless sessions from the CLI, e.g. in a loop or a few in parallel:
t3 auth session issue --ttl 5m --label test --subject test --json - Intermittently the CLI fails immediately with
ServerAuthSessionTokenIssueError whose root cause is database is locked.
Expected behavior
The second writer waits briefly for the lock to clear (standard SQLite busy_timeout behavior) instead of failing instantly.
Actual behavior
ServerAuthSessionTokenIssueError: Failed to issue session token.
[cause]: SessionCredentialIssueError: Failed to issue session credential.
[cause]: PersistenceSqlError: SQL error in AuthSessionRepository.create:query
[cause]: effect/sql/SqlError: Failed to execute statement
[cause]: effect/sql/SqlError/UnknownError: Failed to execute statement
[cause]: Error: database is locked
Root cause
The persistence setup enables WAL but never sets a busy timeout, and the connection is opened without one, so it stays at SQLite's default of 0 ms — any writer-writer collision between the server process and a CLI process on the shared userdata/state.sqlite fails immediately with SQLITE_BUSY.
Setup layer (dist/bin.mjs in v0.0.29, near the migrations bootstrap):
yield*sql`PRAGMA journal_mode = WAL;`;yield*sql`PRAGMA foreign_keys = ON;`;
Connection open (NodeSqliteClient chunk):
newNodeSqlite.DatabaseSync(options.filename,{readOnly: options.readonly??false,allowExtension: options.allowExtension??false});No busy_timeout / timeout anywhere in the bundle.
Suggested fix
Add one pragma to the shared setup layer so every connection (server and CLI) gets it:
yield*sql`PRAGMA busy_timeout = 5000;`;
Verified locally on v0.0.29: with the pragma added, 6 parallel t3 auth session issue calls against a live server succeed 6/6; without it they intermittently fail with database is locked.
This is likely also the root cause behind #4818 (PersistenceSqlError on OrchestrationCommandReceiptRepository.upsert with the cause hidden — PR #4837 will surface it).
Impact
Intermittent failure of any CLI write while the server is running; affects headless/orchestration workflows that issue sessions programmatically.
Version or commit
0.0.29
Environment
Linux (Debian), Node 22.22.1, t3 serve under systemd --user
Workaround
Retry with backoff around CLI calls, or patch the installed bundle with the pragma above.
Before submitting
Area
apps/server
Steps to reproduce
t3 serve, headless deployment).t3 auth session issue --ttl 5m --label test --subject test --jsonServerAuthSessionTokenIssueErrorwhose root cause isdatabase is locked.Expected behavior
The second writer waits briefly for the lock to clear (standard SQLite
busy_timeoutbehavior) instead of failing instantly.Actual behavior
Root cause
The persistence setup enables WAL but never sets a busy timeout, and the connection is opened without one, so it stays at SQLite's default of 0 ms — any writer-writer collision between the server process and a CLI process on the shared
userdata/state.sqlitefails immediately with SQLITE_BUSY.Setup layer (dist/bin.mjs in v0.0.29, near the migrations bootstrap):
Connection open (NodeSqliteClient chunk):
No
busy_timeout/timeoutanywhere in the bundle.Suggested fix
Add one pragma to the shared setup layer so every connection (server and CLI) gets it:
Verified locally on v0.0.29: with the pragma added, 6 parallel
t3 auth session issuecalls against a live server succeed 6/6; without it they intermittently fail withdatabase is locked.This is likely also the root cause behind #4818 (
PersistenceSqlErroronOrchestrationCommandReceiptRepository.upsertwith the cause hidden — PR #4837 will surface it).Impact
Intermittent failure of any CLI write while the server is running; affects headless/orchestration workflows that issue sessions programmatically.
Version or commit
0.0.29
Environment
Linux (Debian), Node 22.22.1,
t3 serveunder systemd --userWorkaround
Retry with backoff around CLI calls, or patch the installed bundle with the pragma above.