paperclipai/paperclip · error · Error
`opencode models` failed: ${detail}
Error message
`opencode models` failed: ${detail} What it means
Thrown by discoverOpenCodeModels (LOCAL) when `opencode models` exits non-zero. The detail is the first non-empty line of stderr then stdout, surfacing opencode's own diagnostic. Same shape as the remote failure (389) but for local discovery.
Source
Thrown at packages/adapters/opencode-local/src/server/models.ts:153
const result = await runChildProcess(
`opencode-models-${Date.now()}-${Math.random().toString(16).slice(2)}`,
command,
["models"],
{
cwd,
env: runtimeEnv,
timeoutSec: MODELS_DISCOVERY_TIMEOUT_MS / 1000,
graceSec: 3,
onLog: async () => {},
},
);
if (result.timedOut) {
throw new Error(`\`opencode models\` timed out after ${MODELS_DISCOVERY_TIMEOUT_MS / 1000}s.`);
}
if ((result.exitCode ?? 1) !== 0) {
const detail = firstNonEmptyLine(result.stderr) || firstNonEmptyLine(result.stdout);
throw new Error(detail ? `\`opencode models\` failed: ${detail}` : "`opencode models` failed.");
}
return sortModels(parseOpenCodeModelsOutput(result.stdout));
}
export async function discoverOpenCodeModelsCached(input: {
command?: unknown;
cwd?: unknown;
env?: unknown;
} = {}): Promise<AdapterModel[]> {
const command = resolveOpenCodeCommand(input.command);
const cwd = asString(input.cwd, process.cwd());
const env = normalizeEnv(input.env);
const key = discoveryCacheKey(command, cwd, env);
const now = Date.now();
pruneExpiredDiscoveryCache(now);
const cached = discoveryCache.get(key);
if (cached && cached.expiresAt > now) return cached.models;View on GitHub (pinned to 67001ec6eb)
Solutions
- Read the detail line — it carries opencode's error (e.g. 'command not found', auth error).
- Install opencode or point PAPERCLIP_OPENCODE_COMMAND at the binary.
- Authenticate the provider on the host (opencode login or API key env).
- Run `opencode models` in the same shell/env to reproduce and fix.
Defensive patterns
Strategy: try-catch
Validate before calling
async function openCodeInstalled(): Promise<boolean> {
try { await runChildProcess("probe", "opencode", ["--version"], { timeoutSec: 5, graceSec: 1, onLog: async () => {} }); return true; } catch { return false; }
} Try / catch
try {
return await discoverOpenCodeModels(input);
} catch (e) {
if (e instanceof Error && /`opencode models` failed/.test(e.message)) {
// surface the detail to the operator; check PATH/PAPERCLIP_OPENCODE_COMMAND and provider auth; non-retryable config issue
}
throw e;
} Prevention
- Ensure opencode is on PATH or set PAPERCLIP_OPENCODE_COMMAND.
- Authenticate providers on the host before discovery.
- Catch in listOpenCodeModels (which already returns [] on error) for non-fatal listing.
When it happens
Trigger: runChildProcess returns exitCode != 0 (not timedOut) for local `opencode models`; detail = firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout).
Common situations: opencode not installed / not on PATH on the host (override with PAPERCLIP_OPENCODE_COMMAND); provider auth missing; corrupt opencode config; version incompatibility.
Related errors
- `opencode models` timed out after ${MODELS_DISCOVERY_TIMEOUT
- `opencode models` failed on the remote execution target: ${d
- OpenCode returned no models. Run `opencode models` and verif
- `pi --list-models` failed: ${detail}
- `opencode models` timed out on the remote execution target a
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/0a85ee532f5ece50.
Report an issue: GitHub.