{"record":{"id":"83fcc3f1d7601e9d","repo":"santifer/career-ops","slug":"wttj-api-env-payload-is-not-valid-json","errorCode":null,"errorMessage":"wttj: /api/env payload is not valid JSON","messagePattern":"wttj: /api/env payload is not valid JSON","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/wttj.mjs","lineNumber":86,"sourceCode":"  }\n  return url;\n}\n\n/**\n * Parse the `window.env = {...}` payload served by /api/env and extract the\n * Algolia application id + client search key.\n * @param {string} text\n * @returns {{ appId: string, apiKey: string }}\n */\nexport function parseEnvPayload(text) {\n  const start = text.indexOf('{');\n  const end = text.lastIndexOf('}');\n  if (start === -1 || end <= start) throw new Error('wttj: /api/env payload has no JSON object');\n  let env;\n  try {\n    env = JSON.parse(text.slice(start, end + 1));\n  } catch {\n    throw new Error('wttj: /api/env payload is not valid JSON');\n  }\n  const appId = typeof env.PUBLIC_ALGOLIA_APPLICATION_ID === 'string' ? env.PUBLIC_ALGOLIA_APPLICATION_ID.trim() : '';\n  const apiKey = typeof env.PUBLIC_ALGOLIA_API_KEY_CLIENT === 'string' ? env.PUBLIC_ALGOLIA_API_KEY_CLIENT.trim() : '';\n  // App ids are short alphanumerics; validating keeps the derived Algolia\n  // hostname from being attacker-shaped if the env payload ever changes.\n  if (!/^[A-Z0-9]{6,16}$/i.test(appId)) throw new Error(`wttj: unexpected Algolia app id \"${appId}\"`);\n  // The key is only ever sent as a request header (never used to build a\n  // host), so don't over-constrain its format — WTTJ may rotate to a longer\n  // or non-hex (e.g. secured/base64) client key. Length bounds only.\n  if (!apiKey || apiKey.length < 16 || apiKey.length > 500) {\n    throw new Error('wttj: unexpected Algolia api key shape');\n  }\n  return { appId, apiKey };\n}\n\n/**\n * Normalize a single Algolia hit. Exported for tests.\n *","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/wttj.mjs#L68-L104","documentation":"After slicing out the {...} region, parseEnvPayload runs JSON.parse on it; if that throws, the text between the outermost braces is not valid JSON. This means /api/env contained brace characters but not a parseable JSON object.","triggerScenarios":"parseEnvPayload given text like 'function() { return x }' or truncated/malformed JSON where the {...} slice fails JSON.parse.","commonSituations":"The env payload changed format (e.g. now a JS script instead of JSON); partial/truncated response due to network issues; an interstitial page containing braces in HTML/JS.","solutions":["Log and inspect the sliced text to see why JSON.parse fails","Retry the fetch to rule out a truncated response","If WTTJ changed the env format, update parseEnvPayload's extraction and key names","Confirm the expected keys (PUBLIC_ALGOLIA_APPLICATION_ID, PUBLIC_ALGOLIA_API_KEY_CLIENT) still exist after parsing"],"exampleFix":"// before\nenv = JSON.parse(text.slice(start, end + 1));\n// after\ntry {\n  env = JSON.parse(text.slice(start, end + 1));\n} catch (e) {\n  throw new Error(`wttj: /api/env payload is not valid JSON: ${e.message}; got: ${text.slice(start, Math.min(start + 200, end + 1))}`);\n}","handlingStrategy":"try-catch","validationCode":"let env;\ntry { env = JSON.parse(text.slice(text.indexOf('{'), text.lastIndexOf('}') + 1)); } catch { throw new Error('env payload not valid JSON'); }\nif (typeof env.PUBLIC_ALGOLIA_APPLICATION_ID !== 'string') throw new Error('env payload missing app id');","typeGuard":"function isValidEnvPayload(env) {\n  return env !== null && typeof env === 'object'\n    && typeof env.PUBLIC_ALGOLIA_APPLICATION_ID === 'string'\n    && typeof env.PUBLIC_ALGOLIA_API_KEY_CLIENT === 'string';\n}","tryCatchPattern":"try { const { appId, apiKey } = parseEnvPayload(text); return { appId, apiKey }; } catch (e) { if (e.message.includes('not valid JSON')) { console.warn('/api/env JSON parse failed; payload format may have changed'); return null; } throw e; }","preventionTips":["Validate the parsed env object's keys immediately after JSON.parse","Keep an archived copy of a known-good /api/env payload to diff against","Wrap JSON.parse in try/catch with the offending text logged for diagnosis"],"tags":["json","json-parse","wttj","payload-parsing"],"backgroundTag":"json-parse-error","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}