{"record":{"id":"a6ba7c091b8db17f","repo":"dubinc/dub","slug":"textdata","errorCode":null,"errorMessage":"textData","messagePattern":"textData","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/parser.ts","lineNumber":21,"sourceCode":"\ntype AnyResponse = Response | NodeFetchResponse;\n\nexport async function parseApiResponse<T>(response: AnyResponse): Promise<T> {\n  const contentType = response.headers.get(\"content-type\");\n\n  if (contentType?.includes(\"application/json\")) {\n    const parsedData = await response.json();\n\n    if (\"error\" in parsedData) {\n      throw new Error((parsedData as APIError).error.message);\n    }\n\n    return parsedData as T;\n  }\n\n  const textData = await response.text();\n\n  throw new Error(textData);\n}\n","sourceCodeStart":3,"sourceCodeEnd":23,"githubUrl":"https://github.com/dubinc/dub/blob/f216b94a24ca5a0a48c6543ee10392c9006c8b75/packages/cli/src/utils/parser.ts#L3-L23","documentation":"When the response content-type is not application/json, parseApiResponse reads the body as text and throws that raw text as the error message. This usually means the request hit something that did not return the Dub JSON API response — a proxy/CDN error page, HTML 502 page, or an outage.","triggerScenarios":"Calls from `dub domains`/defaultDomains when the Dub API (or an intermediary) returns a non-JSON body: HTML error pages from proxies, plain-text 502/503 outage messages, or a wrong base URL hitting a non-API endpoint.","commonSituations":"Corporate proxy or Cloudflare returning an HTML block/timeout page; Dub API downtime; misconfigured DUB_API_BASE/localhost pointing at a UI server instead of the API.","solutions":["Inspect the thrown text — it contains the raw body (e.g. HTML) revealing the real intermediary error.","Retry later or check Dub's status page if the text shows a gateway timeout/502/503.","Verify the API base URL points to https://api.dub.co (or correct env) and not a web UI.","Check proxy/firewall settings that may inject HTML error pages."],"exampleFix":"// before\nbaseUrl = 'https://dub.co'; // hits web app, returns HTML\n// after\nbaseUrl = 'https://api.dub.co';","handlingStrategy":"fallback","validationCode":"const base = process.env.DUB_API_BASE ?? \"https://api.dub.co\";\nnew URL(base); // fail fast on malformed base URL before any request\nif (!base.startsWith(\"https://\")) throw new Error(\"DUB_API_BASE must be an https API endpoint\");","typeGuard":"function isJsonObject(text: string): boolean {\n  try { const v = JSON.parse(text); return typeof v === \"object\" && v !== null; } catch { return false; }\n}","tryCatchPattern":"try {\n  return await parseApiResponse(response);\n} catch (e) {\n  const body = (e as Error).message;\n  if (/<html|502|503|gateway|cloudflare/i.test(body)) {\n    console.error(\"Dub API unreachable (non-JSON response). Retrying later.\");\n    return fallbackValue; // or rethrow after retries\n  }\n  throw e;\n}","preventionTips":["Point the client at the API host (api.dub.co), never the marketing site.","Monitor Dub's status page and add outages to your runbook.","Configure proxies to pass through API hosts without HTML interception.","Distinguish infra failures from API errors by sniffing the thrown text for HTML."],"tags":["api","network","content-type"],"backgroundTag":"non-json-api-response","analyzedSha":"f216b94a24ca5a0a48c6543ee10392c9006c8b75","analyzedAt":"2026-08-31T18:35:50.395Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}