{"record":{"id":"e2b96cbdbb141188","repo":"can1357/oh-my-pi","slug":"opencode-go-usage-endpoint-returned-response-sta","errorCode":null,"errorMessage":"OpenCode Go usage endpoint returned ${response.status}${detail ? `: ${detail}` : \"\"}","messagePattern":"OpenCode Go usage endpoint returned (.+?)(.+?)` : \"\"\\}","errorType":"http","errorClass":"ProviderHttpError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/usage/opencode-go.ts","lineNumber":121,"sourceCode":"\n\tconst url = `${normalizeBaseUrl(params.baseUrl)}${USAGE_PATH}`;\n\tlet payload: unknown;\n\ttry {\n\t\tconst response = await ctx.fetch(url, {\n\t\t\theaders: {\n\t\t\t\taccept: \"application/json\",\n\t\t\t\tauthorization: `Bearer ${credential.apiKey}`,\n\t\t\t},\n\t\t\tsignal: params.signal,\n\t\t});\n\t\tif (!response.ok) {\n\t\t\t// 401 (missing/invalid key) and 403 (no Go subscription) must throw\n\t\t\t// so checkCredentials flags the credential as ok:false rather than\n\t\t\t// ok:null (unknown). Other non-ok statuses are transient — return\n\t\t\t// null so the cached last-good report serves through them.\n\t\t\tif (response.status === 401 || response.status === 403) {\n\t\t\t\tconst detail = await readUpstreamErrorMessage(response);\n\t\t\t\tthrow new ProviderHttpError(\n\t\t\t\t\t`OpenCode Go usage endpoint returned ${response.status}${detail ? `: ${detail}` : \"\"}`,\n\t\t\t\t\tresponse.status,\n\t\t\t\t);\n\t\t\t}\n\t\t\tctx.logger?.warn(\"OpenCode Go usage fetch failed\", {\n\t\t\t\tstatus: response.status,\n\t\t\t\tstatusText: response.statusText,\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\t\tpayload = (await response.json()) as unknown;\n\t} catch (error) {\n\t\tif (error instanceof ProviderHttpError) throw error;\n\t\tctx.logger?.warn(\"OpenCode Go usage fetch error\", { error: String(error) });\n\t\treturn null;\n\t}\n\n\tif (!isRecord(payload) || !isRecord(payload.usage)) {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/usage/opencode-go.ts#L103-L139","documentation":"Thrown by fetchOpenCodeGoUsage when the OpenCode Go usage endpoint returns 401 (missing/invalid key) or 403 (no Go subscription). It deliberately throws — instead of returning null like other statuses — so checkCredentials can mark the credential ok:false (definitively bad) rather than ok:null (unknown). The message may include an upstream error detail read from the response body.","triggerScenarios":"Calling the OpenCode Go usage/credential check with an API key that is absent, revoked, or malformed (401), or with a valid key on an account without an OpenCode Go subscription (403).","commonSituations":"OPENCODE_API_KEY env var unset or containing a placeholder; key rotated or revoked server-side; subscription lapsed or never purchased; key pasted with whitespace or wrong account.","solutions":["For 401, set/replace the OpenCode API key with a valid current credential and retry.","For 403, verify the account has an active OpenCode Go subscription, or upgrade the plan.","Strip whitespace/quotes from the configured key and confirm it belongs to the intended account.","If the key is correct, re-run checkCredentials to confirm ok:false vs ok:null and contact support with the embedded detail."],"exampleFix":"// before\nexport OPENCODE_API_KEY=sk-example-placeholder\n// after\nexport OPENCODE_API_KEY=sk-live-actual-key-from-dashboard","handlingStrategy":"validation","validationCode":"const key = process.env.OPENCODE_API_KEY?.trim();\nif (!key) throw new Error(\"OPENCODE_API_KEY is required for OpenCode Go usage\");\nconst cred = await goProvider.checkCredentials();\nif (cred.ok === false) throw new Error(`OpenCode Go credential invalid: check key/subscription`);","typeGuard":null,"tryCatchPattern":"try {\n\tconst usage = await goProvider.fetchUsage(params);\n} catch (err) {\n\tif (err instanceof AIError.ProviderHttpError && err.status === 401) {\n\t\t// invalid key: reconfigure credential\n\t} else if (err instanceof AIError.ProviderHttpError && err.status === 403) {\n\t\t// no Go subscription: surface upgrade path\n\t} else throw err;\n}","preventionTips":["Run checkCredentials at startup and fail fast on ok:false.","Keep API keys in secret management, not hardcoded; rotate before expiry.","Confirm the subscription is active before deploying usage dashboards."],"tags":["auth","api-key","http-401","http-403","opencode-go"],"backgroundTag":"invalid-api-key","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}