{"record":{"id":"0c2b922d41345c72","repo":"can1357/oh-my-pi","slug":"no-api-key-for-model-provider-model-id","errorCode":null,"errorMessage":"No API key for ${model.provider}/${model.id}","messagePattern":"No API key for (.+?)/(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/git-tui/ai-stage.ts","lineNumber":89,"sourceCode":" * @throws when no model/key resolves, git fails, or every judgement in a pass errors.\n */\nexport async function aiStage(options: AiStageOptions): Promise<AiStageOutcome> {\n\tconst { cwd, instruction, signal, onProgress } = options;\n\tconst repo = vcs.requireGit(cwd);\n\tconst untracked = options.files.filter(file => file.kind === \"untracked\");\n\tconst tracked = options.files.filter(file => file.kind !== \"untracked\" && file.kind !== \"conflicted\");\n\tif (tracked.length === 0 && untracked.length === 0) throw new Error(\"No unstaged changes to filter\");\n\n\tonProgress?.(\"Resolving model…\");\n\tconst settings = await Settings.init({ cwd });\n\tconst authStorage = await discoverAuthStorage();\n\ttry {\n\t\tconst registry = new ModelRegistry(authStorage);\n\t\tawait registry.refresh();\n\t\tawait loadCliExtensionProviders(registry, settings, cwd);\n\t\tconst model = resolveRoleSelection([\"tiny\", \"smol\"], settings, registry.getAvailable())?.model;\n\t\tif (!model) throw new Error(\"No tiny/smol model available for AI staging\");\n\t\tif (!(await registry.getApiKey(model))) throw new Error(`No API key for ${model.provider}/${model.id}`);\n\t\tconst complete = createCompleter(model, registry.resolver(model), signal);\n\n\t\tconst rawDiff = tracked.length > 0 ? await repo.diffText({ files: tracked.map(file => file.path) }, signal) : \"\";\n\t\tconst fileDiffs = new Map(parseFileDiffs(rawDiff).map(entry => [entry.filename, entry]));\n\n\t\tinterface Candidate {\n\t\t\tfile: Pick<ChangedFile, \"path\" | \"kind\">;\n\t\t\t/** Parsed worktree diff; absent for untracked files. */\n\t\t\tdiff?: FileDiff;\n\t\t}\n\t\tconst candidates: Candidate[] = tracked.flatMap(file => {\n\t\t\tconst diff = fileDiffs.get(file.path);\n\t\t\treturn diff ? [{ file, diff }] : [];\n\t\t});\n\t\tcandidates.push(...untracked.map(file => ({ file })));\n\n\t\t// File pass: one completion sees the whole (batched) list, so files are\n\t\t// picked as a coherent set instead of N independent coin flips.","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/git-tui/ai-stage.ts#L71-L107","documentation":"After resolving a tiny/smol model, aiStage verifies that an API key is available for the model's provider via registry.getApiKey. If none is found, it throws with the provider/model id so the user knows exactly which credential is missing. This fails fast before making the request.","triggerScenarios":"A tiny/smol role model resolves from the registry (e.g. anthropic/claude-3-5-haiku) but no API key is stored for that provider in the auth storage (env var absent, no credentials file).","commonSituations":"New machine without provider login, expired/removed credentials, CI environments lacking the provider's API key environment variable, or role pointing at a provider never authenticated.","solutions":["Authenticate with the provider (e.g. run the provider login/API-key setup for omp).","Set the provider's API key environment variable in the shell/CI environment.","Re-point the tiny/smol role at a provider you do have credentials for."],"exampleFix":"// before\nexport PATH=... // no key\n// after\nexport ANTHROPIC_API_KEY=sk-ant-...","handlingStrategy":"validation","validationCode":"const model = resolveRoleSelection([\"tiny\", \"smol\"], settings, registry.getAvailable())?.model;\nif (model && !(await registry.getApiKey(model))) {\n  throw new Error(`Run provider auth for ${model.provider} before AI staging`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await aiStage(opts);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"No API key for\")) {\n    console.error(\"Authenticate the provider first:\", e.message);\n    return;\n  }\n  throw e;\n}","preventionTips":["Complete provider login/API-key setup on every new machine and CI runner.","Set the provider API key env var in shell profiles and CI secrets.","Check registry.getApiKey(model) before enabling AI-stage features."],"tags":["api-key","authentication","configuration"],"backgroundTag":"missing-api-key","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}