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
- 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
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
- 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
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
- init_server requires a wasm source or a
- Missing perspective-client.wasm
- Missing perspective-server.wasm
- perspective-js client wasm has not been compiled yet — call…
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)