AykutSarac/jsoncrack.com · error

JSON parsing failed for graph mode.

Error message

JSON parsing failed for graph mode.

What it means

The content script captures the page body text as rawJson and runs JSON.parse in a useMemo. If parsing throws, the component renders this static error div. It means the page body text — which the extension assumed was a JSON document based on document.contentType — is not parseable JSON, even though the content type claimed it was.

Source

Thrown at apps/chrome-extension/src/content-script.tsx:338

        const message = error instanceof Error ? error.message : "Unable to load graph renderer.";
        setComponentError(message);
      });

    return () => {
      active = false;
    };
  }, []);

  const parsedJson = useMemo(() => {
    try {
      return JSON.parse(rawJson);
    } catch {
      return null;
    }
  }, [rawJson]);

  if (parsedJson === null) {
    return <div id="jsoncrack-graph-error">JSON parsing failed for graph mode.</div>;
  }

  if (componentError) {
    return <div id="jsoncrack-graph-error">Graph renderer error: {componentError}</div>;
  }

  if (!JSONCrackComponent) {
    return <div id="jsoncrack-graph-status">Loading graph renderer...</div>;
  }

  return (
    <div style={{ width: "100%", height: "100%" }}>
      <JSONCrackComponent
        json={parsedJson}
        theme={theme}
        showControls
        showGrid
        centerOnLayout

View on GitHub (pinned to 3c9af69e23)

Solutions

  1. Prefer document.documentElement.textContent or fetch the raw body via the background script.
  2. Trim and attempt a tolerant parse, or strip leading/trailing non-JSON noise.
  3. Detect an HTML doctype and bail early with a clearer message.
  4. Fall back to fetch(location.href) for the canonical response body when accessible.

Example fix

// before
const parsedJson = useMemo(() => {
  try {
    return JSON.parse(rawJson);
  } catch {
    return null;
  }
}, [rawJson]);

// after
const parsedJson = useMemo(() => {
  const trimmed = rawJson.trim();
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
  try {
    return JSON.parse(trimmed);
  } catch {
    return null;
  }
}, [rawJson]);
Defensive patterns

Strategy: validation

Validate before calling

function tryParseRawJson(raw: string): unknown | null {
  const trimmed = raw.trim();
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
  try {
    return JSON.parse(trimmed);
  } catch {
    return null;
  }
}

Type guard

function looksLikeJsonBody(raw: string): boolean {
  const t = raw.trim();
  return (t.startsWith("{") && t.endsWith("}")) || (t.startsWith("[") && t.endsWith("]"));
}

Try / catch

const parsedJson = useMemo(() => tryParseRawJson(rawJson), [rawJson]);
if (parsedJson === null) {
  return <div id="jsoncrack-graph-error">JSON parsing failed for graph mode.</div>;
}

Prevention

When it happens

Trigger: Another JSON-viewer extension already prettified/wrapped the body text; document.body.innerText includes injected UI text around the JSON; truncated or partial response; contentType spoofed; an HTML error page served with a JSON content-type header.

Common situations: Conflicting JSON-viewer extension mutating the DOM; server returning 200 with an HTML body but a JSON content-type; streaming/partial response cut off.

Related errors


AI-assisted analysis of AykutSarac/jsoncrack.com@3c9af69e23 (2026-08-12). Data as JSON: /api/errors/6d5564cfe3b098c1. Report an issue: GitHub.