{"record":{"id":"fd092ea1b474f8fe","repo":"stablyai/orca","slug":"invalid-response-shape","errorCode":null,"errorMessage":"invalid response shape","messagePattern":"invalid response shape","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/github/client.ts","lineNumber":2997,"sourceCode":"    typeof base.ref === 'string' &&\n    base.ref.trim().length > 0 &&\n    (base.sha === undefined || isGitObjectId(base.sha))\n  )\n}\n\nasync function getRestPRByNumber(\n  ownerRepo: GitHubApiRepository,\n  number: number,\n  ghOptions: ReturnType<typeof ghRepoExecOptions>,\n  options: { requireUsableStackMetadata?: boolean } = {}\n): Promise<PullRequestLookupData> {\n  const { stdout } = await ghExecFileAsync(\n    ['api', `repos/${ownerRepo.owner}/${ownerRepo.repo}/pulls/${number}`],\n    { ...ghOptions, ...githubHostExecOptions(ownerRepo) }\n  )\n  const parsed = JSON.parse(stdout) as unknown\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error('invalid response shape')\n  }\n  const restData = parsed as RestPullRequest\n  const mapped = mapRestPullRequest(restData)\n  if (\n    options.requireUsableStackMetadata &&\n    restData.stack !== undefined &&\n    restData.stack !== null\n  ) {\n    // Why: GitHub omits stack for ordinary PRs; only unusable non-null metadata is unsafe.\n    if (!isUsableRestStackMetadata(restData.stack) || !mapped.stack) {\n      throw new Error('malformed stack')\n    }\n    if (!isGitObjectId(restData.head?.sha)) {\n      throw new Error('missing head SHA')\n    }\n  }\n  return mapped\n}","sourceCodeStart":2979,"sourceCodeEnd":3015,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/github/client.ts#L2979-L3015","documentation":"Thrown by getRestPRByNumber after parsing the stdout of `gh api repos/<owner>/<repo>/pulls/<n>`: the parsed JSON is not a plain object (it is null, an array, or a primitive). This is a defensive shape check before the value is cast to RestPullRequest. It indicates the API returned an unexpected body — typically an error envelope, an HTML error page mis-served as 200, or a gh CLI wrapper that emitted non-JSON.","triggerScenarios":"GitHub returned an error envelope with 200 (rare proxy behavior); gh CLI printed a warning line before the JSON; a corporate proxy injected an HTML block page; the API response was truncated mid-stream; gh authenticated against a GitHub Enterprise Server version with a different response shape.","commonSituations":"Corporate MITM proxy returning HTML; gh CLI version mismatch emitting extra stdout; GitHub Enterprise Server older version; flaky network truncating the response body.","solutions":["Reproduce with `gh api repos/<owner>/<repo>/pulls/<n>` in a terminal and inspect the raw output.","If a proxy is injecting HTML, bypass it or add the GitHub host to the no-proxy list.","Upgrade gh CLI to a current version to avoid wrapper noise in stdout.","For GitHub Enterprise, confirm the server version supports the pulls REST shape."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","typeGuard":"function isRestPullRequestShape(v: unknown): v is Record<string, unknown> {\n  return isPlainObject(v) && ('id' in v || 'number' in v || 'head' in v)\n}","tryCatchPattern":"try {\n  const pr = await getRestPRByNumber(ownerRepo, number, ghOptions)\n} catch (err) {\n  if ((err as Error).message === 'invalid response shape') {\n    logRawGhApiOutput(ownerRepo, number) // capture the offending payload\n    toast.error('GitHub returned an unexpected PR payload.')\n  } else throw err\n}","preventionTips":["Inspect raw `gh api` output before assuming shape — proxies can inject HTML.","Bypass corporate proxies for api.github.com where possible.","Keep gh CLI current to avoid wrapper stdout noise."],"tags":["github","api","json-parsing","defense-in-depth","gh-cli"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}