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

  1. Validate event.origin against an allowlist before processing to ignore stray messages.
  2. Try JSON.parse(event.data.json) first and toast the specific parse error message.
  3. Document the expected postMessage payload contract for embedders.
  4. 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

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.