perspective-dev/perspective · error · Error

data script missing for viewer

Error message

data script missing for viewer

What it means

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.

Solutions

  1. Re-export the widget from a viewer that has a table loaded so the arrow data script is embedded
  2. 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
  3. Avoid sanitizers or post-processing that strips script tags from the exported HTML
Defensive patterns

Strategy: validation

Validate before calling

const envelope = document.getElementById(`perspective-envelope-${viewerId}`);
if (!envelope || !envelope.querySelector('script[type="application/vnd.apache.arrow.file"]')) {
  throw new Error(`Exported widget HTML is missing embedded Arrow data for viewer ${viewerId}`);
}

Type guard

const hasArrowData = (envelope) =>
  envelope instanceof HTMLElement &&
  !!envelope.querySelector('script[type="application/vnd.apache.arrow.file"]');

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of perspective-dev/perspective@11c8238c0c (2026-09-09). Data as JSON: /api/errors/5173213258e1f492. Report an issue: GitHub.

Appendix: source

Thrown at rust/perspective-python/perspective/templates/exported_widget.html.template:25

<div class="perspective-envelope" id="perspective-envelope-$viewer_id">
    <script type="application/vnd.apache.arrow.file">
    $b64_data
    </script>
    <perspective-viewer style="height: 690px;"></perspective-viewer>
    <script type="module">
        // from MDN
        function base64ToBytes(base64) {
            const binString = atob(base64);
            return Uint8Array.from(binString, (m) => m.codePointAt(0));
        }

        import * as perspective from "$psp_cdn_perspective";
        const viewerId = "$viewer_id";
        const currentScript = document.scripts[document.scripts.length - 1];
        const envelope = document.getElementById(`perspective-envelope-$${viewerId}`);
        const dataScript = envelope.querySelector('script[type="application/vnd.apache.arrow.file"]');
        if (!dataScript)
            throw new Error('data script missing for viewer', viewerId);
        const data = base64ToBytes(dataScript.textContent);
        const viewerAttrs = $viewer_attrs;

        // Create a new worker, then a new table on that worker. `worker()`
        // sources the client wasm from the registered `<perspective-viewer>`
        // Custom Element, which registers asynchronously.
        await customElements.whenDefined("perspective-viewer");
        const client = await perspective.worker();
        const table = await client.table(data.buffer);
        const viewer = envelope.querySelector('perspective-viewer');
        viewer.load(table);
        viewer.restore(viewerAttrs);
    </script>
</div>

View on GitHub (pinned to 11c8238c0c)