{"record":{"id":"15f997031d983f1f","repo":"aaif-goose/goose","slug":"unknown-provider-providerid","errorCode":null,"errorMessage":"Unknown provider: ${providerId}","messagePattern":"Unknown provider: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/desktop/src/acp/providers.ts","lineNumber":120,"sourceCode":"  const { entries } = await client.goose.providersList_unstable({});\n  return entries.map(providerEntryToDetails);\n}\n\nexport async function acpListSetupProviderDetails(): Promise<ProviderDetails[]> {\n  const providers = await acpListProviderDetails();\n  return providers.filter((provider) => provider.visible_in_setup);\n}\n\nexport async function acpListSettingsProviderDetails(): Promise<ProviderDetails[]> {\n  const providers = await acpListProviderDetails();\n  return providers.filter((provider) => provider.visible_in_setup || provider.is_configured);\n}\n\nexport async function acpGetProviderDetails(providerId: string): Promise<ProviderDetails> {\n  const client = await getAcpClient();\n  const { entries } = await client.goose.providersList_unstable({ providerIds: [providerId] });\n  const entry = entries.find((candidate) => candidate.providerId === providerId);\n  if (!entry) throw new Error(`Unknown provider: ${providerId}`);\n  return providerEntryToDetails(entry);\n}\n\nasync function waitForProviderInventoryRefresh(\n  client: Awaited<ReturnType<typeof getAcpClient>>,\n  providerId: string,\n  refresh: RefreshProviderInventoryResponse_unstable,\n  signal?: globalThis.AbortSignal\n): Promise<ProviderDetails> {\n  const shouldWait =\n    refresh.started.includes(providerId) ||\n    refresh.skipped?.some(\n      (skip) => skip.providerId === providerId && skip.reason === 'already_refreshing'\n    );\n\n  let entry: ProviderInventoryEntryDto | undefined;\n  const attempts = shouldWait\n    ? INVENTORY_REFRESH_TIMEOUT_MS / INVENTORY_REFRESH_POLL_INTERVAL_MS","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/acp/providers.ts#L102-L138","documentation":"Thrown by acpGetProviderDetails: it sends providersList_unstable({providerIds: [providerId]}) and searches response.entries for a matching providerId. The goose backend returns an entry only for ids it knows (built-in or registered providers), so a miss means the id does not exist in the backend's provider inventory — different from 'not configured'. This is a client-side guard before providerEntryToDetails would dereference undefined.","triggerScenarios":"Calling acpGetProviderDetails('openai ') with a typo or whitespace; an id from an older/newer goose version (provider renamed or removed); a custom provider not yet registered in the profile; entries returned under a different providerId spelling (case-sensitive compare).","commonSituations":"Persisted provider id in settings/localStorage after upgrading goose; hand-edited config referencing a deleted provider; UI list rendered from a cached inventory while the backend inventory changed.","solutions":["Call acpListProviderDetails() (or acpListSettingsProviderDetails) and print the available providerIds — use an exact id from that list.","Check for trailing spaces/case mismatch in the id; the find is an exact === on providerId.","If the id came from persisted settings, clear or migrate it after a goose upgrade that renamed providers.","Confirm the backend version: providersList_unstable is an _unstable API and its inventory can change between releases."],"exampleFix":"// before\nconst { entries } = await client.goose.providersList_unstable({ providerIds: [providerId] });\nconst entry = entries.find((candidate) => candidate.providerId === providerId);\nif (!entry) throw new Error(`Unknown provider: ${providerId}`);\n\n// after (fail with the ids that do exist)\nconst { entries } = await client.goose.providersList_unstable({ providerIds: [providerId] });\nconst entry = entries.find((candidate) => candidate.providerId === providerId);\nif (!entry) {\n  const all = await client.goose.providersList_unstable({ providerIds: [] });\n  throw new Error(`Unknown provider: ${providerId}. Available: ${all.entries.map((e) => e.providerId).join(', ')}`);\n}","handlingStrategy":"type-guard","validationCode":"// Resolve the id against the live inventory before fetching details\nconst known = await acpListProviderDetails();\nconst validId = known.find((p) => p.id === providerId)?.id;\nif (!validId) {\n  throw new Error(`Provider '${providerId}' is not in the inventory. Available: ${known.map((p) => p.id).join(', ')}`);\n}","typeGuard":"async function isKnownProvider(providerId: string): Promise<boolean> {\n  const providers = await acpListProviderDetails();\n  return providers.some((p) => p.id === providerId);\n}","tryCatchPattern":"try {\n  const details = await acpGetProviderDetails(providerId);\n} catch (error) {\n  if (/Unknown provider/.test(String(error))) {\n    return refreshProviderListUi(); // repopulate picker from the inventory\n  }\n  throw error;\n}","preventionTips":["Always populate provider pickers from providersList_unstable output, never from a hardcoded list.","Trim whitespace and match casing exactly — the lookup is a strict === on providerId.","Drop persisted provider ids after goose upgrades that rename providers."],"tags":["acp","providers","validation","unstable-api"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}