{"record":{"id":"c67eb9bca10654eb","repo":"ruvnet/ruflo","slug":"unexpected-shape","errorCode":"unexpected_shape","errorMessage":"unexpected response shape from the server","messagePattern":"unexpected response shape from the server","errorType":"exception","errorClass":"OAuthError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/security/src/oauth/client.ts","lineNumber":75,"sourceCode":"/** Builds the `/oauth/authorize` URL for the standard loopback-redirect flow. */\nexport function authorizeUrl(redirectUri: string, state: string, codeChallenge: string): string {\n  const url = new URL(`${authBaseUrl()}/oauth/authorize`);\n  url.searchParams.set('response_type', 'code');\n  url.searchParams.set('client_id', CLIENT_ID);\n  url.searchParams.set('redirect_uri', redirectUri);\n  url.searchParams.set('scope', SCOPE);\n  url.searchParams.set('state', state);\n  url.searchParams.set('code_challenge', codeChallenge);\n  url.searchParams.set('code_challenge_method', 'S256');\n  return url.toString();\n}\n\nasync function parseTokenResponse(resp: Response): Promise<TokenResponse> {\n  if (resp.ok) {\n    try {\n      return (await resp.json()) as TokenResponse;\n    } catch {\n      throw new OAuthError('unexpected response shape from the server', 'unexpected_shape');\n    }\n  }\n  try {\n    const body = (await resp.json()) as OAuthErrorBody;\n    throw new OAuthError(\n      `oauth error: ${body.error} — ${body.error_description}`,\n      'protocol',\n      body.error,\n      body.error_description,\n    );\n  } catch (e) {\n    if (e instanceof OAuthError) throw e;\n    throw new OAuthError('unexpected response shape from the server', 'unexpected_shape');\n  }\n}\n\nasync function postForm(path: string, form: Record<string, string>, base = authBaseUrl()): Promise<TokenResponse> {\n  let resp: Response;","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/security/src/oauth/client.ts#L57-L93","documentation":"parseTokenResponse got a 2xx from the token endpoint but resp.json() failed — the body isn't JSON — so it throws OAuthError code 'unexpected_shape'. The client only speaks the JSON token format, so a 200 with an HTML/text body means something other than the OAuth server answered.","triggerScenarios":"A captive portal or transparent proxy intercepting the POST and returning a 200 login page; COGNITUM_AUTH_URL pointing at a server that doesn't implement POST /oauth/token; an API gateway returning 200 with an HTML error shell.","commonSituations":"Corporate networks with SSL inspection portals; leftover COGNITUM_AUTH_URL from local testing aimed at a stub; a misconfigured load balancer answering 200 for every path.","solutions":["Unset or fix COGNITUM_AUTH_URL — the default is https://auth.cognitum.one","Reproduce manually: curl -i -X POST $COGNITUM_AUTH_URL/oauth/token and inspect status, content-type, and body","Rule out HTTPS_PROXY/captive-portal interception; retry from a clean network","If you operate the server, never return 200 with non-JSON on the token route"],"exampleFix":"# before\nexport COGNITUM_AUTH_URL=http://localhost:3000 # dev stub returning HTML → unexpected_shape\n\n# after\nunset COGNITUM_AUTH_URL # target https://auth.cognitum.one","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isOAuthError(e: unknown, code?: string): boolean {\n  return e instanceof Error && e.name === 'OAuthError'\n    && (code === undefined || (e as { code?: string }).code === code);\n}","tryCatchPattern":"try {\n  return await postToken(form);\n} catch (e) {\n  if (isOAuthError(e, 'unexpected_shape')) {\n    // something answered 200 that isn't the OAuth server: check COGNITUM_AUTH_URL / proxies\n    throw new Error(`Auth server returned non-JSON 200 — check COGNITUM_AUTH_URL and network interception`);\n  }\n  throw e;\n}","preventionTips":["Point COGNITUM_AUTH_URL only at servers that actually implement the OAuth token endpoints","Reproduce unexpected shapes with curl -i before guessing at code fixes","Distrust 200 responses with non-JSON content-type in OAuth clients generally"],"tags":["oauth","json","proxy","configuration"],"backgroundTag":"invalid-json-response","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}