Pi file-writing turn fails with Actor SQLite transaction timeout on local native runtime #1973
Description
Problem
A minimal Pi file-writing prompt fails with session_storage_error and an Actor SQLite transaction timeout on the local native runtime. This reproduces outside our application, using published packages without patches or overrides.
The official Pi quickstart directory-listing prompt succeeds in 8.7 seconds. Asking Pi to write one small file fails, including as the first prompt on a fresh actor. Direct filesystem.writeFile/readFile calls worked in earlier checks; the failing operation is the complete agent turn and its durable session storage.
Environment
- macOS, Apple Silicon; Node.js 24.19.0
@rivet-dev/agentos: 0.2.19@rivet-dev/agentos-core: 0.2.19, supplied by agentOS@agentos-software/pi: 0.2.7rivetkitand local Engine: 2.3.10, matching agentOS dependencies- Anthropic credential supplied through
sessions.open({ env }) - Local native actor runtime, not Rivet Cloud and not embedded Core
Reproduction
In a new directory, initialise a private ESM package and install:
pnpm add @rivet-dev/agentos@0.2.19 @agentos-software/pi@0.2.7 rivetkit@2.3.10server.mjs, matching the official Pi server example:
import { agentOS, setup } from '@rivet-dev/agentos';
import pi from '@agentos-software/pi';
const vm = agentOS({ software: [pi] });
export const registry = setup({ use: { vm } });
registry.start();Start with isolated local storage and a free port:
RIVET_RUN_ENGINE=1 RIVET_RUN_ENGINE_HOST=127.0.0.1 RIVET_RUN_ENGINE_PORT=6720 RIVET_RUN_SERVICES=0 RIVETKIT_STORAGE_PATH="$PWD/data" node server.mjsNo inherited remote Rivet endpoint or custom sidecar override was present. The server reports http://127.0.0.1:6720 (local native) and one actor.
client.mjs, with ANTHROPIC_API_KEY set in its environment:
import { createClient } from '@rivet-dev/agentos/client';
const client = createClient({ endpoint: 'http://127.0.0.1:6720' });
const agent = client.vm.getOrCreate('fresh-write');
try {
if (!process.env.ANTHROPIC_API_KEY) throw new Error('Missing key');
await agent.sessions.open({
agent: 'pi',
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
});
const result = await agent.sessions.prompt({
content: [{ type: 'text', text:
'Write /home/agentos/proof.txt containing exactly PI_ACTOR_OK.' }],
});
console.log(result.stopReason);
if (result.stopReason !== 'end_turn') throw new Error('Turn did not complete');
console.log(new TextDecoder().decode(
await agent.filesystem.readFile('/home/agentos/proof.txt')));
} finally {
await client.dispose();
}Actual result
The fresh session opens in about one second. The prompt fails:
session_storage_error: actor SQLite UDS failed:
actor SQLite UDS transaction lease expired after 30000ms:
SQLite transaction expired after 30000 ms and was rolled back.
A further test retained agent.connect(), received live sessionEvent tool updates, explicitly set permissionPolicy: 'allow_all', used a single-write prompt, and configured options: { sleepTimeout: 10 * 60_000 } on the server. It still failed on a fresh actor. No vmShutdown event arrived before the failure. That server logged:
slow sqlite transaction duration_ms=30002 statement_count=3 commit_round_trips=0
operation=execute
sql="SELECT COALESCE(MAX(generation), 0) FROM agentos_fs_metadata_chunks WHERE namespace = ?"
code=transaction_expired
The client reported session_storage_error: actor SQLite UDS connection generation closed: request deadline expired in that variant.
Expected result
The turn returns end_turn, the file contains PI_ACTOR_OK, and the completed session can be resumed. Is there a required local-runtime setting or supported package combination missing from this setup?
Reference: official Pi example at the 0.2.19 source revision.
Activity
Jona1han commentedon Sep 12, 2026
Hi @NathanFlurry - I hit #1973 while building a custom Cursor ACP harness on agentOS 0.2.19. I reproduced and fixed it locally, and I’d be happy to open a PR. I’ve also worked on integrating Cursor with agentOS and could propose that separately if it would be useful.
Here is what my agent wrote:
Native thread stacks showed a LocalSet wait cycle: a synchronous mounted-filesystem read blocked the main thread while persisting atime; that SQLite request was parked behind an active history transaction; and the transaction needed the same LocalSet thread to continue. The 30-second lease timeout eventually broke the cycle.
My two-file fix runs each complete actor-UDS SQLite transaction on the existing bounded runtime worker pool. It preserves statement ordering and commit/rollback behavior. Once admitted, transactions finish even if their caller stops waiting, matching the local SQLite backend.
The deterministic regression fails before the change and passes afterward. All 11 native SQLite/VFS integration tests and 18 session/history-store tests pass. I also verified three consecutive Cursor turns and confirmed that history survived a refresh.
Since 0.2.19 was released from the still-open #1947 branch rather than main, would you prefer:
a stacked PR against workspace/brave-valley-1778; or
a commit/patch you can cherry-pick or adapt while reworking #1947?
I’m happy to provide either or both.