{"record":{"id":"cd57f0cda1a1e905","repo":"apache/echarts","slug":"component-maintype-subtype-is-used-but-not-imp","errorCode":null,"errorMessage":"Component {mainType}.{subType} is used but not imported.","messagePattern":"Component (.+?)\\.(.+?) is used but not imported\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/util/clazz.ts","lineNumber":289,"sourceCode":"                container[componentTypeInfo.sub] = clz;\n            }\n        }\n        return clz;\n    };\n\n    target.getClass = function (\n        mainType: ComponentMainType,\n        subType?: ComponentSubType,\n        throwWhenNotFound?: boolean\n    ): Constructor {\n        let clz = storage[mainType];\n\n        if (clz && (clz as SubclassContainer)[IS_CONTAINER]) {\n            clz = subType ? (clz as SubclassContainer)[subType] : null;\n        }\n\n        if (throwWhenNotFound && !clz) {\n            throw new Error(\n                !subType\n                    ? mainType + '.' + 'type should be specified.'\n                    : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.'\n            );\n        }\n\n        return clz as Constructor;\n    };\n\n    target.getClassesByMainType = function (componentType: ComponentFullType): Constructor[] {\n        const componentTypeInfo = parseClassType(componentType);\n\n        const result: Constructor[] = [];\n        const obj = storage[componentTypeInfo.main];\n\n        if (obj && (obj as SubclassContainer)[IS_CONTAINER]) {\n            zrUtil.each(obj as SubclassContainer, function (o, type) {\n                type !== IS_CONTAINER && result.push(o as Constructor);","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/apache/echarts/blob/30076aedcd7b7f65d8dd8e8d9ece46ce778133a3/src/util/clazz.ts#L271-L307","documentation":"Thrown by the same `getClass(mainType, subType, throwWhenNotFound)` in clazz.ts:289, but on the `subType` branch: a specific component subtype was requested (e.g. `series.graph`, `visualMap.piecewise`), the main type's subclass container existed, yet no class was registered under that sub-key. The message 'Component X.Y is used but not imported.' is ECharts' canonical signal that the chart/component subtype referenced in the option was never registered. Like error 41, this throw is not gated by `__DEV__` and can fire in production.","triggerScenarios":"The option contains `series: [{ type: 'graph' | 'line' | 'bar' | ... }]` (or a component with a subtype such as `visualMap: { type: 'piecewise' }`) while the matching submodule (GraphChart, LineChart, etc.) was omitted from `echarts.use([...])` in an on-demand build. `parseClassType` splits `series.graph` into main=`series`, sub=`graph`; the sub is absent from the container so getClass returns null and throws.","commonSituations":"The single most common ECharts on-demand mistake — forgetting one chart or component subtype in the `.use([...])` list; a dynamic/conditional option that includes a chart type registered only on some code paths; upgrading ECharts where a subtype was renamed or removed; a custom series whose model/view was never registered.","solutions":["Import and register the named chart/component before setOption: e.g. `import { GraphChart } from 'echarts/charts'; echarts.use([GraphChart]);` (use the subtype from the message).","Cross-check every `type` value across `series` and component options against the entries in your `echarts.use([...])` array.","Ensure registration runs before `chart.setOption(...)` and before any async option merge.","For zero-config convenience (larger bundle), use the full bundle `import * as echarts from 'echarts';` which registers all built-in subtypes."],"exampleFix":"// before\nimport * as echarts from 'echarts/core';\nimport { BarChart } from 'echarts/charts';\necharts.use([BarChart]); // 'Component series.graph is used but not imported.'\nconst option = { series: [{ type: 'graph', data: [...], links: [...] }] };\n\n// after\nimport * as echarts from 'echarts/core';\nimport { BarChart, GraphChart } from 'echarts/charts';\necharts.use([BarChart, GraphChart]);\nconst option = { series: [{ type: 'graph', data: [...], links: [...] }] };","handlingStrategy":"validation","validationCode":"// Collect every chart/component subtype used in the option and report any not\n// present in your explicit registration allow-list.\nfunction findUnregisteredSubtypes(option, registeredTypes) {\n  const used = new Set();\n  (option.series || []).forEach(s => s && s.type && used.add('series.' + s.type));\n  ['visualMap', 'dataZoom', 'legend'].forEach(k =>\n    [].concat(option[k] || []).forEach(c => c && c.type && used.add(k + '.' + c.type)));\n  return [...used].filter(t => !registeredTypes.has(t));\n}\n// const missing = findUnregisteredSubtypes(option, new Set(['series.bar','series.line']));","typeGuard":"function isRegisteredSubtype(echartsRef, fullType) {\n  // echarts has no public hasClass; use a probe instance + try/catch as the guard.\n  const probe = echartsRef.init(document.createElement('div'));\n  const [main, sub] = fullType.split('.');\n  try {\n    probe.setOption(main === 'series' ? { series: [{ type: sub, data: [] }] } : { [main]: [{ type: sub }] });\n    return true;\n  } catch { return false; } finally { probe.dispose(); }\n}","tryCatchPattern":null,"preventionTips":["Treat the `echarts.use([...])` array as a contract: any new `type` added to an option must be added there in the same change.","Generate the registration list from a single source (e.g. a config array of supported chart/component types) so option validation and `.use()` cannot drift.","In CI, run a parametric test that calls `setOption` for each supported subtype to catch missing imports before release."],"tags":["on-demand-import","chart-registration","component","configuration"],"backgroundTag":null,"analyzedSha":"30076aedcd7b7f65d8dd8e8d9ece46ce778133a3","analyzedAt":"2026-08-12T12:42:28.134Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}