santifer/career-ops · error · Error
wttj: unexpected Algolia api key shape
Error message
wttj: unexpected Algolia api key shape
What it means
The parsed PUBLIC_ALGOLIA_API_KEY_CLIENT must be non-empty and 16–500 chars. The bounds are deliberately wide (the comment notes WTTJ may rotate to longer/base64/secured keys) since the key is only ever sent as a request header, never used to build a host. Throws when the key is missing/renamed or outside the length bounds.
Source
Thrown at providers/wttj.mjs:72
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.
*
* Field mapping → normalized Job shape:
* - title: `name`
* - url: /en/companies/{organization.slug}/jobs/{slug} on the WTTJ site
* - company: `organization.name`
* - location: offices[0] city+country, with ", Remote" appended when the
* posting allows fulltime remote
* - postedAt: `published_at_timestamp` (epoch seconds → ms)
* - salary: {min, max, currency} from salary_yearly_minimum/salary_maximum
*
* @param {any} h
* @returns {{ title: string, url: string, company: string, location: string, postedAt?: number, salary?: {min: number, max: number, currency: string} } | null}View on GitHub (pinned to 9b17a8ac97)
Solutions
- Fetch /api/env and verify PUBLIC_ALGOLIA_API_KEY_CLIENT is present and non-empty.
- If the key was renamed, update the field read in parseEnvPayload.
- If the key genuinely grew past 500 chars, raise the upper bound after confirming.
- If /api/env was truncated, retry the fetch.
Example fix
// if the env key is renamed: // before const apiKey = typeof env.PUBLIC_ALGOLIA_API_KEY_CLIENT === "string" ? env.PUBLIC_ALGOLIA_API_KEY_CLIENT.trim() : ""; // after const apiKey = typeof env.PUBLIC_ALGOLIA_SEARCH_KEY === "string" ? env.PUBLIC_ALGOLIA_SEARCH_KEY.trim() : "";
Defensive patterns
Strategy: validation
Validate before calling
if (typeof parsedApiKey !== "string" || parsedApiKey.length < 16 || parsedApiKey.length > 500)
console.warn("wttj api key shape changed — length:", parsedApiKey?.length); Type guard
const isValidAlgoliaApiKey = (s) => typeof s === "string" && s.length >= 16 && s.length <= 500;
Try / catch
try { parseEnvPayload(envText); }
catch (err) {
if (/Algolia api key shape/.test(err.message)) { logUpstreamChange("wttj", err.message); }
throw err;
} Prevention
- Alert on this error to catch a key rename or rotation.
- Re-fetch /api/env each run so a rotated key self-heals.
- Only widen the length bounds after confirming the new key shape.
When it happens
Trigger: /api/env no longer contains PUBLIC_ALGOLIA_API_KEY_CLIENT; the field was renamed; WTTJ rotated to a key shorter than 16 or longer than 500 chars (extremely unlikely); a truncated /api/env response cut off the key.
Common situations: WTTJ renamed the env key; the env object parsed but the key field is absent; a truncated response.
Related errors
- wttj: unexpected Algolia app id "${appId}"
- wttj: unexpected Algolia response for query "${query}" — exp
- wttj: untrusted ${label} hostname "${parsed.hostname}" — mus
- wttj: /api/env payload has no JSON object
- wttj: /api/env payload is not valid JSON
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/62ee3dae4fa106ca.
Report an issue: GitHub.