{"record":{"id":"bcc84fe2b0fff729","repo":"paperclipai/paperclip","slug":"pi-list-models-timed-out","errorCode":null,"errorMessage":"`pi --list-models` timed out.","messagePattern":"`pi --list-models` timed out\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapters/pi-local/src/server/models.ts","lineNumber":127,"sourceCode":"  const cwd = asString(input.cwd, process.cwd());\n  const env = normalizeEnv(input.env);\n  const runtimeEnv = normalizeEnv({ ...process.env, ...env });\n\n  const result = await runChildProcess(\n    `pi-models-${Date.now()}-${Math.random().toString(16).slice(2)}`,\n    command,\n    [\"--list-models\"],\n    {\n      cwd,\n      env: runtimeEnv,\n      timeoutSec: 20,\n      graceSec: 3,\n      onLog: async () => {},\n    },\n  );\n\n  if (result.timedOut) {\n    throw new Error(\"`pi --list-models` timed out.\");\n  }\n  if ((result.exitCode ?? 1) !== 0) {\n    const detail = firstNonEmptyLine(result.stderr) || firstNonEmptyLine(result.stdout);\n    throw new Error(detail ? `\\`pi --list-models\\` failed: ${detail}` : \"`pi --list-models` failed.\");\n  }\n\n  // Pi outputs model list to stderr, but fall back to stdout for older versions\n  const output = result.stderr || result.stdout;\n  return sortModels(dedupeModels(parseModelsOutput(output)));\n}\n\nfunction normalizeEnv(input: unknown): Record<string, string> {\n  const envInput = typeof input === \"object\" && input !== null && !Array.isArray(input)\n    ? (input as Record<string, unknown>)\n    : {};\n  const env: Record<string, string> = {};\n  for (const [key, value] of Object.entries(envInput)) {\n    if (typeof value === \"string\") env[key] = value;","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapters/pi-local/src/server/models.ts#L109-L145","documentation":"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.","triggerScenarios":"runChildProcess for `pi --list-models` returns { timedOut: true }.","commonSituations":"pi binary slow to start (cold cache, antivirus); pi hanging on a provider network call; pi prompting interactively in a non-TTY; overloaded host.","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)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async function piResponsive(timeoutMs = 5000): Promise<boolean> {\n  try {\n    const r = await runChildProcess(\"pi-probe\", \"pi\", [\"--version\"], { timeoutSec: timeoutMs/1000, graceSec: 1, onLog: async () => {} });\n    return (r.exitCode ?? 1) === 0;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"let attempt = 0;\nwhile (true) {\n  try {\n    return await discoverPiModels(input);\n  } catch (e) {\n    if (e instanceof Error && /`pi --list-models` timed out/.test(e.message) && attempt++ < 1) continue;\n    throw e;\n  }\n}","preventionTips":["Pre-authenticate the pi provider so enumeration is fast.","Confirm the pi binary path resolves correctly.","Avoid running discovery under heavy host load."],"tags":["pi","models","timeout","discovery"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}