AykutSarac/jsoncrack.com · error · Error

Unable to parse data.

Error message

Unable to parse data.

What it means

The fallback Error constructed in parseJsonGraph (canvasHelpers.ts:87) when the synchronous parseGraph call throws something that is NOT an Error instance (e.g. a string, number, or null thrown by a dependency). parseJsonGraph wraps the whole parse in try/catch and returns a discriminated { kind:"error", error } result instead of throwing, so callers never see a raw throw. When the thrown value is already an Error it is preserved verbatim; only non-Error throws get this generic message.

Source

Thrown at packages/jsoncrack-react/src/canvasHelpers.ts:87

  | { kind: "ok"; graph: GraphData; syntaxErrorCount: number }
  | { kind: "above-limit"; total: number }
  | { kind: "error"; error: Error };

/** Parse a JSON text into a graph, returning a discriminated result instead of throwing or touching React state. */
export const parseJsonGraph = (
  jsonText: string,
  maxRenderableNodes: number
): ParseJsonGraphResult => {
  try {
    const graph = parseGraph(jsonText);
    if (graph.nodes.length > maxRenderableNodes) {
      return { kind: "above-limit", total: graph.nodes.length };
    }
    return { kind: "ok", graph, syntaxErrorCount: graph.errors.length };
  } catch (error) {
    return {
      kind: "error",
      error: error instanceof Error ? error : new Error("Unable to parse data."),
    };
  }
};

/** Build a map from edge id → target node id for O(1) lookups in edge renderers. */
export const buildEdgeTargetMap = (edges: GraphData["edges"]): Map<string, string> => {
  const targetById = new Map<string, string>();
  for (let i = 0; i < edges.length; i += 1) {
    const edge = edges[i];
    targetById.set(edge.id, edge.to);
  }
  return targetById;
};

/** Toggle reaflow's `dragging` class on the canvas div to suppress pointer events during long-press panning. */
export const setCanvasDragging = (container: HTMLElement | null, dragging: boolean): void => {
  const canvas = container?.querySelector(".jsoncrack-canvas") as HTMLElement | null;
  if (!canvas) return;

View on GitHub (pinned to 3c9af69e23)

Solutions

  1. Inspect the actual thrown value: temporarily log `error` in the catch to see if it carries a real message before the generic fallback applies.
  2. Validate/size-limit input before parsing (guard against pathological depth or size).
  3. Ensure the thrown value is an Error upstream so its message is preserved instead of being replaced by the generic text.
  4. If reproducing, isolate whether calculateNodeSize or getNodePath is the real throw site by unit-testing parseGraph directly.

Example fix

// before
return {
  kind: "error",
  error: error instanceof Error ? error : new Error("Unable to parse data."),
};

// after — preserve non-Error throw context for diagnostics
return {
  kind: "error",
  error:
    error instanceof Error
      ? error
      : new Error(`Unable to parse data. (thrown: ${typeof error} ${String(error)})`),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Reject pathological inputs before parsing (depth/size guards)
export function isSafeToParse(text: string, maxBytes = 5_000_000, maxDepth = 500): boolean {
  if (text.length > maxBytes) return false;
  let depth = 0;
  for (const ch of text) {
    if (ch === "{" || ch === "[") depth++;
    if (ch === "}" || ch === "]") depth--;
    if (depth > maxDepth) return false;
  }
  return true;
}

Type guard

// Narrow the discriminated parse result
export function isParseError(r: { kind: string }): r is { kind: "error"; error: Error } {
  return r.kind === "error";
}

Try / catch

// parseJsonGraph never throws — handle the discriminated result
const result = parseJsonGraph(jsonText, maxRenderableNodes);
if (result.kind === "error") {
  // result.error.message may be "Unable to parse data." for non-Error throws
  report(result.error);
}

Prevention

When it happens

Trigger: parseGraph (parser.ts) delegates to jsonc-parser's parseTree/getNodePath and to calculateNodeSize. If any of those throw a non-Error value, or if a future change throws a primitive, the catch builds `new Error("Unable to parse data.")`. Realistically this path is rare because jsonc-parser does not throw on bad input (it reports errors in the collector); it would require a bug in calculateNodeSize or a corrupted node value (e.g. a circular value reaching value.toString()).

Common situations: A dependency regression that throws a primitive; extremely large/deeply-nested JSON causing a stack overflow inside traversal that surfaces as a thrown string; monkey-patched prototypes interfering with node.value.toString().

Understand the failure class

Related errors


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