AykutSarac/jsoncrack.com · error
error
Error message
error
What it means
The embed/widget page listens for postMessage events from the parent frame. When the parent sends data.json, setContents parses and transforms it via contentToJson; if the payload is not valid JSON for the configured format the store throws and this catch logs it and toasts 'Invalid JSON!'. The error means the embedding site sent malformed JSON or a non-JSON string.
Source
Thrown at apps/www/src/pages/widget.tsx:68
else clearJson();
window.parent.postMessage(window.frameElement?.getAttribute("id"), "*");
}
}, [checkEditorSession, clearJson, isReady, push, query.json, query.partner]);
React.useEffect(() => {
const handler = (event: EmbedMessage) => {
try {
if (!event.data?.json) return;
if (event.data?.options?.theme === "light" || event.data?.options?.theme === "dark") {
setTheme(event.data.options.theme);
toggleDarkMode(event.data.options.theme === "dark");
}
setContents({ contents: event.data.json, hasChanges: false });
setDirection(event.data.options?.direction || "RIGHT");
} catch (error) {
console.error(error);
toast.error("Invalid JSON!");
}
};
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, [setColorScheme, setContents, setDirection, toggleDarkMode, theme]);
React.useEffect(() => {
setColorScheme(theme);
}, [setColorScheme, theme]);
return (
<ThemeProvider theme={theme === "dark" ? darkTheme : lightTheme}>
<Head>{generateNextSeo({ noindex: true, nofollow: true })}</Head>
<ModalController />
<div style={{ width: "100vw", height: "100vh" }}>
<GraphView isWidget />View on GitHub (pinned to 3c9af69e23)
Solutions
- Validate event.origin against an allowlist before processing to ignore stray messages.
- Try JSON.parse(event.data.json) first and toast the specific parse error message.
- Document the expected postMessage payload contract for embedders.
- Apply the same literal-narrowing used for options.theme to the json field.
Example fix
// before
const handler = (event: EmbedMessage) => {
try {
if (!event.data?.json) return;
setContents({ contents: event.data.json, hasChanges: false });
} catch (error) {
console.error(error);
toast.error("Invalid JSON!");
}
};
// after
const handler = (event: MessageEvent) => {
const data = event.data as EmbedMessage["data"];
if (!data?.json) return;
try {
JSON.parse(data.json);
} catch (e) {
toast.error(e instanceof Error ? e.message : "Invalid JSON!");
return;
}
try {
setContents({ contents: data.json, hasChanges: false });
} catch (error) {
console.error(error);
toast.error("Invalid JSON!");
}
}; Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED_ORIGINS = ["https://embed.example.com"];
function isTrustedEmbedEvent(event: MessageEvent): boolean {
if (!ALLOWED_ORIGINS.includes(event.origin)) return false;
const data = event.data as EmbedMessage["data"];
if (!data?.json || typeof data.json !== "string") return false;
try {
JSON.parse(data.json);
return true;
} catch {
return false;
}
} Type guard
function isEmbedMessageData(data: unknown): data is EmbedMessage["data"] {
if (!data || typeof data !== "object") return false;
const d = data as Record<string, unknown>;
if (d.json !== undefined && typeof d.json !== "string") return false;
return true;
} Try / catch
const handler = (event: MessageEvent) => {
if (!isTrustedEmbedEvent(event)) return;
try {
setContents({ contents: (event.data as EmbedMessage["data"]).json!, hasChanges: false });
} catch (error) {
console.error(error);
toast.error("Invalid JSON!");
}
}; Prevention
- Always validate event.origin against an allowlist before trusting postMessage data.
- JSON.parse the incoming json before setContents to give a precise error.
- Document the postMessage payload contract for embedders and reject anything that does not match.
When it happens
Trigger: Parent frame calls postMessage({ data: { json: '{not json}' } }); parent sends JSON with trailing commas/comments that JSON.parse rejects; format mismatch (parent sends YAML but widget defaults to JSON); an unrelated cross-origin script posts a message whose data.json is coincidentally a non-JSON string.
Common situations: Third-party embed sending an un-stringified object instead of a JSON string; copy-paste with smart quotes corrupting the payload; React DevTools or another extension posting messages that loosely match the shape; missing event.origin validation letting stray messages through.
Related errors
AI-assisted analysis of AykutSarac/jsoncrack.com@3c9af69e23 (2026-08-12).
Data as JSON: /api/errors/9b872e0c52e704bd.
Report an issue: GitHub.