{"record":{"id":"6320450b284b5f57","repo":"Stirling-Tools/Stirling-PDF","slug":"unexpected-json-structure-expected-an-object-at-r","errorCode":null,"errorMessage":"Unexpected JSON structure (expected an object at root).","messagePattern":"Unexpected JSON structure \\(expected an object at root\\)\\.","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"warning","filePath":"scripts/analyze_pdf_json.py","lineNumber":221,"sourceCode":"\ndef main() -> None:\n    parser = argparse.ArgumentParser(description=\"Inspect a PDF JSON export.\")\n    parser.add_argument(\"json_path\", type=Path, help=\"Path to the JSON export.\")\n    args = parser.parse_args()\n\n    json_path = args.json_path\n    if not json_path.exists():\n        raise SystemExit(f\"File not found: {json_path}\")\n\n    file_size = json_path.stat().st_size\n    print(f\"File: {json_path}\")\n    print(f\"Size: {human_bytes(file_size)} ({file_size:,} bytes)\")\n\n    with json_path.open(\"r\", encoding=\"utf-8\") as handle:\n        document = json.load(handle)\n\n    if not isinstance(document, dict):\n        raise SystemExit(\"Unexpected JSON structure (expected an object at root).\")\n\n    summary = analyze_document(document, file_size)\n    page_stats = summary.pages\n    print(f\"Pages: {page_stats.page_count}\")\n    print(f\"Total text elements: {page_stats.total_text_elements:,}\")\n    print(f\"Total image elements: {page_stats.total_image_elements:,}\")\n    print(\n        f\"Page structural bytes (text arrays + images + streams + annotations): \"\n        f\"{human_bytes(page_stats.text_struct_bytes + page_stats.image_struct_bytes + page_stats.content_stream_bytes + page_stats.annotations_bytes)}\"\n    )\n\n    font_stats = summary.fonts\n    print(\"\\nFont summary:\")\n    print(f\"  Fonts total: {font_stats.total}\")\n    print(f\"  Fonts with cosDictionary: {font_stats.with_cos}\")\n    print(f\"  Fonts with program: {font_stats.with_program}\")\n    print(f\"  Fonts with webProgram: {font_stats.with_web_program}\")\n    print(f\"  Fonts with pdfProgram: {font_stats.with_pdf_program}\")","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/scripts/analyze_pdf_json.py#L203-L239","documentation":"SystemExit raised by analyze_pdf_json.py when the parsed JSON root is not an object (dict). The analyzer expects a Stirling PDF JSON export whose root is an object containing keys like fonts, pages, metadata. A JSON array, primitive, or malformed export at the root fails this check.","triggerScenarios":"The file contains valid JSON but the root is an array (e.g. a list of pages) or a scalar, not the expected object shape. The file is a different JSON format mistaken for a PDF export.","commonSituations":"Pointing the analyzer at the wrong JSON file (e.g. a raw page array export, a config file). A truncated/corrupted export that parsed to a partial structure. An upstream change to the export schema.","solutions":["Confirm the file is a Stirling PDF text-editor JSON export (should have top-level 'pages', 'fonts', 'metadata').","Re-export the PDF from the editor.","Inspect the file root with: python -c \"import json;print(type(json.load(open('file.json'))))\"."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Confirm the root is an object with expected keys before analysis\nif not isinstance(document, dict) or not {\"pages\", \"fonts\"} <= document.keys():\n    raise SystemExit(\"Not a Stirling PDF JSON export (missing pages/fonts at root).\")","typeGuard":"def is_pdf_export(document: object) -> bool:\n    return isinstance(document, dict) and \"pages\" in document and \"fonts\" in document","tryCatchPattern":null,"preventionTips":["Confirm the file is a Stirling PDF export (has pages/fonts at root).","Re-export from the editor if the structure is wrong.","Inspect the root type before analysis."],"tags":["cli","json","python","validation","scripts","data-integrity"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}