{"record":{"id":"00b7bf51e20f528e","repo":"perspective-dev/perspective","slug":"unknown-chart-tag-tag","errorCode":null,"errorMessage":"Unknown chart tag: ${tag}","messagePattern":"Unknown chart tag: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/viewer-charts/src/ts/worker/renderer.worker.ts","lineNumber":76,"sourceCode":"\n/**\n * Renderer state. One per host element. In worker mode it lives in\n * the worker; in in-process mode (host loads this module via dynamic\n * `import(workerURL)`) it lives on the main thread. The class itself\n * doesn't care — both modes drive it through a `MessagePort` of\n * `ControlMsg`s.\n */\n/**\n * Resolve a chart tag to its impl class via the lazy registry. Eager\n * tags microtask-resolve; map tags trigger a dynamic `import()` that\n * the bundler emits as a separately-fetched chunk.\n */\nasync function resolveChartImpl(\n    tag: string,\n): Promise<new () => ChartImplementation> {\n    const factory = CHART_IMPLS[tag];\n    if (!factory) {\n        throw new Error(`Unknown chart tag: ${tag}`);\n    }\n\n    return await factory();\n}\n\n/**\n * Renderer-scope shared context pool for pooled blit mode. Lazily\n * created on first use so non-blit / non-pooled scopes never allocate\n * one. One per renderer scope (the worker, or the main thread in\n * in-process mode) — `WorkerRenderer`s in the same scope share its K\n * contexts.\n */\nlet CONTEXT_POOL: ContextPool | null = null;\n\nfunction getContextPool(precompile: boolean): ContextPool {\n    if (!CONTEXT_POOL) {\n        CONTEXT_POOL = new ContextPool(RENDER_CONTEXT_POOL_SIZE, {\n            precompile,","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/perspective-dev/perspective/blob/11c8238c0c9c0b9e490b5a6a2dc277afad1e980a/packages/viewer-charts/src/ts/worker/renderer.worker.ts#L58-L94","documentation":"The worker renderer maps a chart tag string to a lazily-imported ChartImplementation factory in the CHART_IMPLS registry. When resolveChartImpl receives a tag that has no registered factory, it throws this Error instead of returning a constructor. This guards the worker against messages requesting chart types the build does not know about.","triggerScenarios":"Sending a renderer message whose chart tag string is not a key of CHART_IMPLS — e.g. a typo ('barchart' vs 'bar-chart'), a chart type from a newer/older version of the package, or a tag constructed dynamically from user input.","commonSituations":"Host page and worker bundles are version-skewed (worker updated, main thread not, or vice versa) so the main thread sends tags the worker build lacks; misspelled tag in chart configuration; custom chart registered only on the main thread, never in the worker's CHART_IMPLS map.","solutions":["Log/print the exact ${tag} value from the message and compare it against the keys of CHART_IMPLS in renderer.worker.ts.","Fix the tag spelling or use a supported chart tag from the registry.","Rebuild and deploy the worker and main-thread bundles from the same package version so their chart tag sets match.","If it's a custom chart, register its factory in CHART_IMPLS in the worker bundle.","Validate chart tags at the API boundary on the main thread before posting the message, to fail fast with a clearer error."],"exampleFix":"// before\nworker.postMessage({ type: \"render\", tag: \"barchart\" });\n// after (use the registered tag)\nworker.postMessage({ type: \"render\", tag: \"bar-chart\" });","handlingStrategy":"validation","validationCode":"const KNOWN_TAGS = new Set(Object.keys(CHART_IMPLS));\nfunction isKnownChartTag(tag: string): boolean {\n  return KNOWN_TAGS.has(tag);\n}\n// call before posting the render message\nif (!isKnownChartTag(cfg.tag)) throw new Error(`Unsupported chart tag: ${cfg.tag}`);","typeGuard":"function isChartTag(tag: string): tag is keyof typeof CHART_IMPLS {\n  return tag in CHART_IMPLS;\n}","tryCatchPattern":"try {\n  await renderer.render(msg);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Unknown chart tag\")) {\n    console.warn(`Falling back: ${e.message}`);\n    await renderer.render({ ...msg, tag: \"table\" });\n  } else throw e;\n}","preventionTips":["Use the exported chart tag union/enum type instead of raw strings in chart config.","Version-lock the main-thread and worker bundles so their registries match.","Validate chart tags at the main-thread API boundary before posting worker messages.","Register any custom chart in the worker's CHART_IMPLS map, not just the main thread."],"tags":["worker","registry","unknown-identifier","webassembly"],"backgroundTag":"invalid-enum-value","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"}