DIYgod/RSSHub · error · Error
Failed to parse embedded script JSON: ${error.message}
Error message
Failed to parse embedded script JSON: ${error.message} What it means
Thrown when the double JSON.parse of the data-iso script text fails. ScienceRedirect stores its payload as a JSON string inside a JSON envelope (hence JSON.parse(JSON.parse(...))), and any malformed/oddly-encoded content surfaces here with the underlying parse error attached via the cause option.
Source
Thrown at lib/routes/sciencedirect/call-for-paper.tsx:41
description: '`sciencedirect.com/browse/calls-for-papers?subject=education` -> `/sciencedirect/call-for-paper/education`',
};
async function handler(ctx) {
const { subject = '' } = ctx.req.param();
const apiUrl = `https://www.sciencedirect.com/browse/calls-for-papers?subject=${subject}`;
const response = await got(apiUrl);
const $ = load(response.body);
const scriptJSON = $('script[data-iso-key="_0"]').text();
if (!scriptJSON) {
throw new Error('Cannot find the script with data-iso-key="_0"');
}
let data;
try {
data = JSON.parse(JSON.parse(scriptJSON));
} catch (error: any) {
throw new Error(`Failed to parse embedded script JSON: ${error.message}`, { cause: error });
}
const cfpList = data?.callsForPapers?.list || [];
if (!cfpList.length) {
throw new Error('No Calls for Papers found');
}
const items = cfpList.map((cfp) => {
const link = `https://www.sciencedirect.com/special-issue/${cfp.contentId}/${cfp.url}`;
const description = renderToString(
<div>
<p>
<strong>Summary:</strong> {cfp.summary}
</p>
<p>
<strong>Submission Deadline:</strong> {cfp.submissionDeadline}
</p>
<p>View on GitHub (pinned to bed535e087)
Solutions
- Log scriptJSON to inspect its actual encoding (single vs double JSON, HTML-escaping).
- If single-encoded now, replace JSON.parse(JSON.parse(scriptJSON)) with a single JSON.parse.
- If the content is HTML-escaped, unescape (he.decode) before parsing.
- Keep the try/catch but include the body length and a snippet in the rethrown error.
Example fix
// before
try {
data = JSON.parse(JSON.parse(scriptJSON));
} catch (error: any) {
throw new Error(`Failed to parse embedded script JSON: ${error.message}`, { cause: error });
}
// after — try double, fall back to single encoding
try {
try {
data = JSON.parse(JSON.parse(scriptJSON));
} catch {
data = JSON.parse(scriptJSON);
}
} catch (error: any) {
throw new Error(`Failed to parse embedded script JSON: ${error.message}`, { cause: error });
} Defensive patterns
Strategy: try-catch
Validate before calling
// Normalize the script text (unescape HTML entities) and try single then double parse.
function parseIsoPayload(raw: string): unknown {
const unescaped = raw.replace(/"/g, '"').replace(/&/g, '&');
try {
return JSON.parse(unescaped);
} catch {
return JSON.parse(JSON.parse(unescaped));
}
} Type guard
const isPlainObject = (v: unknown): v is Record<string, unknown> =>
typeof v === 'object' && v !== null && !Array.isArray(v); Try / catch
let data: unknown;
try {
data = JSON.parse(JSON.parse(scriptJSON));
} catch {
try {
data = JSON.parse(scriptJSON); // single-encoded fallback
} catch (error: any) {
throw new Error(`Failed to parse embedded script JSON: ${error.message}`, { cause: error });
}
} Prevention
- Detect the encoding depth dynamically (try single, then double) instead of assuming double.
- Capture a real scriptJSON sample in a fixture to regression-test the parser.
- Keep the cause option so the original SyntaxError is preserved for debugging.
When it happens
Trigger: scriptJSON is non-empty but JSON.parse(JSON.parse(scriptJSON)) throws — the inner parse produces a non-string, or the outer parse hits invalid JSON (e.g. the payload is now single-encoded HTML-escaped, or contains unescaped characters).
Common situations: ScienceDirect switched from double-encoded to single-encoded JSON; the payload now contains escaped sequences that break strict parsing; a partial/chunked response produced truncated JSON; cheerio's .text() decoded entities the encoder didn't expect.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- No Calls for Papers found
- Cannot find the script with data-iso-key="_0"
- Unknown handled type: ${element.type}, ${JSON.stringify(elem
- Unable to decode the Locals server response.
- Unable to resolve the Locals community metadata.
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/a4e9691bf77e8311.
Report an issue: GitHub.