paperclipai/paperclip · error · Error
`pi --list-models` timed out.
Error message
`pi --list-models` timed out.
What it means
Thrown by discoverPiModels (pi-local) when the `pi --list-models` child process does not finish within 20s (timeoutSec=20, graceSec=3). The Pi adapter enumerates models via this CLI call, and a hang prevents any model discovery.
Source
Thrown at packages/adapters/pi-local/src/server/models.ts:127
const cwd = asString(input.cwd, process.cwd());
const env = normalizeEnv(input.env);
const runtimeEnv = normalizeEnv({ ...process.env, ...env });
const result = await runChildProcess(
`pi-models-${Date.now()}-${Math.random().toString(16).slice(2)}`,
command,
["--list-models"],
{
cwd,
env: runtimeEnv,
timeoutSec: 20,
graceSec: 3,
onLog: async () => {},
},
);
if (result.timedOut) {
throw new Error("`pi --list-models` timed out.");
}
if ((result.exitCode ?? 1) !== 0) {
const detail = firstNonEmptyLine(result.stderr) || firstNonEmptyLine(result.stdout);
throw new Error(detail ? `\`pi --list-models\` failed: ${detail}` : "`pi --list-models` failed.");
}
// Pi outputs model list to stderr, but fall back to stdout for older versions
const output = result.stderr || result.stdout;
return sortModels(dedupeModels(parseModelsOutput(output)));
}
function normalizeEnv(input: unknown): Record<string, string> {
const envInput = typeof input === "object" && input !== null && !Array.isArray(input)
? (input as Record<string, unknown>)
: {};
const env: Record<string, string> = {};
for (const [key, value] of Object.entries(envInput)) {
if (typeof value === "string") env[key] = value;View on GitHub (pinned to 67001ec6eb)
Solutions
- Run `pi --list-models` manually to identify what it is waiting on.
- Pre-authenticate the pi provider so enumeration does not block on auth.
- Verify the pi binary path (resolvePiCommand) points at a working install.
- If the hang is a known transient, retry discovery (the cache TTL will then hold the result).
Defensive patterns
Strategy: retry
Validate before calling
async function piResponsive(timeoutMs = 5000): Promise<boolean> {
try {
const r = await runChildProcess("pi-probe", "pi", ["--version"], { timeoutSec: timeoutMs/1000, graceSec: 1, onLog: async () => {} });
return (r.exitCode ?? 1) === 0;
} catch { return false; }
} Try / catch
let attempt = 0;
while (true) {
try {
return await discoverPiModels(input);
} catch (e) {
if (e instanceof Error && /`pi --list-models` timed out/.test(e.message) && attempt++ < 1) continue;
throw e;
}
} Prevention
- Pre-authenticate the pi provider so enumeration is fast.
- Confirm the pi binary path resolves correctly.
- Avoid running discovery under heavy host load.
When it happens
Trigger: runChildProcess for `pi --list-models` returns { timedOut: true }.
Common situations: pi binary slow to start (cold cache, antivirus); pi hanging on a provider network call; pi prompting interactively in a non-TTY; overloaded host.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- `opencode models` timed out after ${MODELS_DISCOVERY_TIMEOUT
- `pi --list-models` failed: ${detail}
- `opencode models` timed out on the remote execution target a
- `opencode models` failed: ${detail}
- OpenCode returned no models. Run `opencode models` and verif
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/bcc84fe2b0fff729.
Report an issue: GitHub.