santifer/career-ops · error · Error
wttj: /api/env payload is not valid JSON
Error message
wttj: /api/env payload is not valid JSON
What it means
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.
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
Example fix
// before
env = JSON.parse(text.slice(start, end + 1));
// after
try {
env = JSON.parse(text.slice(start, end + 1));
} catch (e) {
throw new Error(`wttj: /api/env payload is not valid JSON: ${e.message}; got: ${text.slice(start, Math.min(start + 200, end + 1))}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
let env;
try { env = JSON.parse(text.slice(text.indexOf('{'), text.lastIndexOf('}') + 1)); } catch { throw new Error('env payload not valid JSON'); }
if (typeof env.PUBLIC_ALGOLIA_APPLICATION_ID !== 'string') throw new Error('env payload missing app id'); Type guard
function isValidEnvPayload(env) {
return env !== null && typeof env === 'object'
&& typeof env.PUBLIC_ALGOLIA_APPLICATION_ID === 'string'
&& typeof env.PUBLIC_ALGOLIA_API_KEY_CLIENT === 'string';
} Try / catch
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; } Prevention
- 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
When it happens
Trigger: parseEnvPayload given text like 'function() { return x }' or truncated/malformed JSON where the {...} slice fails JSON.parse.
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- wttj: /api/env payload has no JSON object
- collage: unrecognized response envelope (expected a…
- Could not parse existing candidates file at
- each entry needs a string "input" and "output"
- Existing candidates file at
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/83fcc3f1d7601e9d.
Report an issue: GitHub.
Appendix: source
Thrown at providers/wttj.mjs:86
}
return url;
}
/**
* Parse the `window.env = {...}` payload served by /api/env and extract the
* Algolia application id + client search key.
* @param {string} text
* @returns {{ appId: string, apiKey: string }}
*/
export function parseEnvPayload(text) {
const start = text.indexOf('{');
const end = text.lastIndexOf('}');
if (start === -1 || end <= start) throw new Error('wttj: /api/env payload has no JSON object');
let env;
try {
env = JSON.parse(text.slice(start, end + 1));
} catch {
throw new Error('wttj: /api/env payload is not valid JSON');
}
const appId = typeof env.PUBLIC_ALGOLIA_APPLICATION_ID === 'string' ? env.PUBLIC_ALGOLIA_APPLICATION_ID.trim() : '';
const apiKey = typeof env.PUBLIC_ALGOLIA_API_KEY_CLIENT === 'string' ? env.PUBLIC_ALGOLIA_API_KEY_CLIENT.trim() : '';
// App ids are short alphanumerics; validating keeps the derived Algolia
// hostname from being attacker-shaped if the env payload ever changes.
if (!/^[A-Z0-9]{6,16}$/i.test(appId)) throw new Error(`wttj: unexpected Algolia app id "${appId}"`);
// The key is only ever sent as a request header (never used to build a
// host), so don't over-constrain its format — WTTJ may rotate to a longer
// or non-hex (e.g. secured/base64) client key. Length bounds only.
if (!apiKey || apiKey.length < 16 || apiKey.length > 500) {
throw new Error('wttj: unexpected Algolia api key shape');
}
return { appId, apiKey };
}
/**
* Normalize a single Algolia hit. Exported for tests.
*View on GitHub (pinned to aac998c7ed)