{"record":{"id":"5173213258e1f492","repo":"perspective-dev/perspective","slug":"data-script-missing-for-viewer","errorCode":null,"errorMessage":"data script missing for viewer","messagePattern":"data script missing for viewer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"rust/perspective-python/perspective/templates/exported_widget.html.template","lineNumber":25,"sourceCode":"<div class=\"perspective-envelope\" id=\"perspective-envelope-$viewer_id\">\n    <script type=\"application/vnd.apache.arrow.file\">\n    $b64_data\n    </script>\n    <perspective-viewer style=\"height: 690px;\"></perspective-viewer>\n    <script type=\"module\">\n        // from MDN\n        function base64ToBytes(base64) {\n            const binString = atob(base64);\n            return Uint8Array.from(binString, (m) => m.codePointAt(0));\n        }\n\n        import * as perspective from \"$psp_cdn_perspective\";\n        const viewerId = \"$viewer_id\";\n        const currentScript = document.scripts[document.scripts.length - 1];\n        const envelope = document.getElementById(`perspective-envelope-$${viewerId}`);\n        const dataScript = envelope.querySelector('script[type=\"application/vnd.apache.arrow.file\"]');\n        if (!dataScript)\n            throw new Error('data script missing for viewer', viewerId);\n        const data = base64ToBytes(dataScript.textContent);\n        const viewerAttrs = $viewer_attrs;\n\n        // Create a new worker, then a new table on that worker. `worker()`\n        // sources the client wasm from the registered `<perspective-viewer>`\n        // Custom Element, which registers asynchronously.\n        await customElements.whenDefined(\"perspective-viewer\");\n        const client = await perspective.worker();\n        const table = await client.table(data.buffer);\n        const viewer = envelope.querySelector('perspective-viewer');\n        viewer.load(table);\n        viewer.restore(viewerAttrs);\n    </script>\n</div>\n","sourceCodeStart":7,"sourceCodeEnd":40,"githubUrl":"https://github.com/perspective-dev/perspective/blob/11c8238c0c9c0b9e490b5a6a2dc277afad1e980a/rust/perspective-python/perspective/templates/exported_widget.html.template#L7-L40","documentation":"The exported_widget.html template embeds a serialized Arrow table as a base64 <script type=\"application/vnd.apache.arrow.file\"> tag inside a per-viewer envelope. The embedded JS throws when that script tag cannot be found for the given viewerId, meaning the exported widget HTML was generated without data or the envelope was mutated/truncated before the inline script ran.","triggerScenarios":"Loading an exported perspective widget page where the envelope element `perspective-envelope-<viewerId>` contains no script[type=\"application/vnd.apache.arrow.file\"] — e.g. export ran with no table data, a manually edited/truncated HTML file, or DOM sanitization stripped the script tag.","commonSituations":"Opening a hand-edited exported widget HTML; posting the HTML through a sanitizer/CMS that removes script tags; exporting a viewer that had no table loaded; copy/pasting partial HTML.","solutions":["Re-export the widget from a viewer that has a table loaded so the arrow data script is embedded","Check the exported HTML for `<script type=\"application/vnd.apache.arrow.file\">` inside the envelope element and ensure the envelope id matches the viewer id in the inline script","Avoid sanitizers or post-processing that strips script tags from the exported HTML"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const envelope = document.getElementById(`perspective-envelope-${viewerId}`);\nif (!envelope || !envelope.querySelector('script[type=\"application/vnd.apache.arrow.file\"]')) {\n  throw new Error(`Exported widget HTML is missing embedded Arrow data for viewer ${viewerId}`);\n}","typeGuard":"const hasArrowData = (envelope) =>\n  envelope instanceof HTMLElement &&\n  !!envelope.querySelector('script[type=\"application/vnd.apache.arrow.file\"]');","tryCatchPattern":"try { initExportedWidget(viewerId); } catch (e) { if (e.message === 'data script missing for viewer') { renderError(`Widget export is missing data; re-export with a loaded table`); } else throw e; }","preventionTips":["Only export widgets after a table is loaded in the viewer","Do not hand-edit or sanitize exported widget HTML (script tags carry the data)","Verify the exported HTML contains the arrow script tag before distributing it"],"tags":["browser","html","missing-data"],"backgroundTag":"resource-not-found","analyzedSha":"11c8238c0c9c0b9e490b5a6a2dc277afad1e980a","analyzedAt":"2026-09-09T00:35:19.377Z","contentChangedAt":"2026-09-09T00:35:19.377Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}