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
- Inspect the actual thrown value: temporarily log `error` in the catch to see if it carries a real message before the generic fallback applies.
- Validate/size-limit input before parsing (guard against pathological depth or size).
- Ensure the thrown value is an Error upstream so its message is preserved instead of being replaced by the generic text.
- 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
- Treat any non-Error thrown value as a bug in upstream parser utilities — fix the throw site.
- Size/depth-limit input before parsing to avoid stack overflows in traversal.
- Unit-test parseGraph directly with adversarial inputs to surface the real throw.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse data (${syntaxErrorCount} syntax error(s)).
- error.message
- This graph has ${totalNodes} nodes and exceeds the maxRender
- Failed to fetch JSON!
- Invalid Schema
AI-assisted analysis of AykutSarac/jsoncrack.com@3c9af69e23 (2026-08-12).
Data as JSON: /api/errors/a4c6fdfd43b80f1d.
Report an issue: GitHub.