santifer/career-ops · error · Error
wttj: /api/env payload has no JSON object
Error message
wttj: /api/env payload has no JSON object
What it means
parseEnvPayload extracts the substring between the first { and the last } of the /api/env response (the window.env = {...} block). This throws when there is no { at all, or no } after it — i.e. the response contains no JSON-object-looking span.
Source
Thrown at providers/wttj.mjs:56
throw new Error(`wttj: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`wttj: URL must use HTTPS: ${url}`);
if (parsed.hostname !== host.toLowerCase()) {
throw new Error(`wttj: untrusted ${label} hostname "${parsed.hostname}" — must be ${host}`);
}
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 };View on GitHub (pinned to 9b17a8ac97)
Solutions
- Fetch https://www.welcometothejungle.com/api/env in a browser and confirm it still contains a window.env = {...} block.
- If it is an error page, retry later.
- If WTTJ changed the bootstrap, update parseEnvPayload's extraction to match (scope to the window.env assignment).
- Check the HTTP status — a non-200 may be masked by a 200 HTML page.
Example fix
// before — relies on literal window.env braces anywhere in the page
const start = text.indexOf("{");
const end = text.lastIndexOf("}");
if (start === -1 || end <= start) throw new Error("wttj: /api/env payload has no JSON object");
// after — find the window.env assignment explicitly
const m = text.match(/window\.env\s*=\s*(\{[\s\S]*\})\s*;?\s*<\/?script/i);
if (!m) throw new Error("wttj: /api/env payload has no JSON object");
let env;
try { env = JSON.parse(m[1]); }
catch { throw new Error("wttj: /api/env payload is not valid JSON"); } Defensive patterns
Strategy: try-catch
Validate before calling
const text = await fetch(ENV_URL).then(r => r.text());
if (text.indexOf("{") === -1 || text.lastIndexOf("}") <= text.indexOf("{")) {
console.warn("wttj /api/env has no JSON object — possible maintenance page");
} Type guard
const hasJsonObject = (t) => typeof t === "string" &&
t.indexOf("{") !== -1 && t.lastIndexOf("}") > t.indexOf("{"); Try / catch
let creds;
try {
creds = parseEnvPayload(envText);
} catch (err) {
if (/\/api\/env payload/.test(err.message)) { logUpstreamChange("wttj", err.message); }
throw err;
} Prevention
- Smoke-test /api/env in CI to catch a markup change early.
- Alert on this error — it almost always means WTTJ changed something.
- Distinguish a transient error page from a permanent markup change by retrying once.
When it happens
Trigger: /api/env returned an HTML error page, an empty body, plain text, or a payload whose braces are in the wrong order. Most often a transient error page from WTTJ/CDN, or a permanent markup change at WTTJ (no more literal window.env = {...}).
Common situations: WTTJ is returning a 200 HTML error/maintenance page; a CDN interstitial; WTTJ refactored the env bootstrap so it is no longer a literal window.env assignment.
Related errors
- wttj: /api/env payload is not valid JSON
- wttj: unexpected Algolia app id "${appId}"
- wttj: unexpected Algolia api key shape
- wttj: unexpected Algolia response for query "${query}" — exp
- echojobs: unexpected API response on page ${page} — expected
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/252433f5a7445d6c.
Report an issue: GitHub.