Errors and warnings
Every error the chart raises and every warning it logs has a stable code. This page lists them all with their cause and fix. Errors are ChartErrors (see Errors for how they reach you); warnings are console.warn lines in development builds only, in the form:
charton [option-unknown]: applyOptions: unknown option "crossHair" is ignored; did you mean "crosshair"? (…/errors.md#option-unknown)The part before the message names the call that took the value. Each warning is logged once per call and key. Both lists are exported, CHART_ERROR_CODES and DEV_WARNING_CODES, for apps that map codes to their own messages.
Development warnings
Development builds check the options passed to createChart, applyOptions, addPane, every add* series call and series.applyOptions, drawing styles in drawings.add and drawings.update, and createChartShell and shell.applyFeatures in @chart-on/ui. Production builds skip the checks and leave them out of the bundle: any bundler that replaces process.env.NODE_ENV with 'production' drops them (most do in a production build). Code loaded without a bundler has no process and stays quiet. The script-tag build is a production build: it leaves the checks out, also when a bundler imports it.
The checks never change what the chart does: an unknown key is still ignored and a wrong value is still used as given, as in production.
Using a deprecated API logs charton [deprecated]: ... once per page load, also in development builds only, with the replacement and a link to its entry on the upgrading page.
option-unknown
An options object has a key the chart does not know, often a typo such as crossHair or bodyColour. The warning names the closest known key when there is one. Fix the key, or remove it. Drawing styles are open to fields of plugin tools, so they only report keys that look like a misspelt known one.
option-type
A value has the wrong type, such as a string for barSpacing or a boolean where an object is expected. The warning says what the option takes. Pass that type; undefined and null are always accepted.
option-range
A number outside its documented range (a negative columnRatio, a bodyRatio above 1), a fraction where a whole number is needed, NaN, or a string that is not one of the values the option takes (legend.mode: 'tiny'). Pass a value from the range or list in the warning.
Loading a layout logs it too when the layout's chart style is one this version does not draw, such as hlcArea, which was renamed rangeBand. The main series then draws candles, and the layout's errors list mainSeries.style; nothing throws. Save the layout again to store the style shown now. A chart style starred in the shell's favourites under such a name shows as candles in the favourites strip and logs it as well; the stored reference is kept.
option-color
A colour string the chart cannot read, such as '#12'. Use a hex, rgb()/rgba() or other CSS colour; colours that depend on where they are used (currentColor, light-dark()) cannot be drawn either. Without a DOM (tests, server rendering) only hex and rgb() strings are checked.
time-milliseconds
The newest time in setData is above 10^11, which looks like milliseconds. Times are unix seconds: divide by 1000.
time-fraction
A time in setData is not a whole second. Intervals are whole seconds, so fractional times are usually a conversion slip; round them.
search-route-failed
A route of createDataSourceRouter failed to search symbols; its error is in the message. It is logged once per route. The other routes' results are still shown, and the search fails only when every route does. Fix the route's source, or pass the router's onError option to handle the failure yourself, which also silences the warning.
marker-icon
A bar marker's icon.image is a Blob the browser could not decode, for example not an image or a format it does not support. The marker draws without its icon (its text still shows). Pass an image the browser can decode, or decode it yourself and pass the ImageBitmap.
adjustments-missing
The data source reports corporate actions (adjustments) and the adjustment option or adjustmentMarkers asks for them, but the chart has no adjustments() plugin, so the bars show as sent and no action is marked. Logged once per page load. Create the chart with adjustments() (or builtins()) in its plugins, or call chart.install(adjustments()); the loaded bars are then adjusted without fetching again.
annotations-missing
Something that draws through annotations arrived on a chart without the annotations() plugin: marks or time marks from the data source, corporate action markers, or an indicator's shape plots. Nothing shows until the plugin is added. Logged once per page load. Create the chart with annotations() (or builtins()) in its plugins, or call chart.install(annotations()); what arrived before shows once it is there.
watermark-missing
The chart was given features: { watermark: true }, but it has no watermark() plugin, so no watermark shows, and reading chart.watermark throws not-registered. Logged once per page load. Create the chart with watermark() (or builtins()) in its plugins, or call chart.install(watermark()); it then shows the symbol and interval loaded. A watermark made with createWatermark and attached with chart.attachPrimitive needs no plugin.
reference-lines-missing
The chart was given a referenceLines option that turns a line on, but it has no referenceLines() plugin, so no line shows, and reading chart.referenceLines throws not-registered. Logged once per page load. Create the chart with referenceLines() (or builtins()) in its plugins, or call chart.install(referenceLines()); it then applies the option kept so far.
price-styles-missing
A candle series was drawn in the kagi or pointFigure style on a chart without the priceStyles() plugin, so it draws nothing. This is a warning, not an error: nothing throws, and the series keeps its style, so layouts and settings that use it still load. Logged once per page load. Create the chart with priceStyles() (or builtins()) in its plugins, or call chart.install(priceStyles()); the series then draws on the next frame.
grouping-missing
The chart was given a grouping option, but it has no grouping() plugin, so bars draw singly, zooming stops at minBarSpacing, and chart.grouping stays null. Logged once per page load. Create the chart with grouping() (or builtins()) in its plugins, or call chart.install(grouping()); the view then groups bars on the next frame.
pulse-missing
A series has a lastPointPulse option that rings, but the chart has no lastPointPulse() plugin, so no ring or dot draws. Logged once per page load. Create the chart with lastPointPulse() (or builtins()) in its plugins, or call chart.install(lastPointPulse()); an 'on-update' pulse then rings on the next live update, and a 'continuous' one on the next frame. Nothing throws, and the option is kept as given.
countdown-missing
The chart was given features: { countdown: true }, but it has no countdown() plugin, so no time left in the newest bar shows under the last price label. Logged once per page load. The flag is on by default, so only an explicit true warns. Create the chart with countdown() (or builtins()) in its plugins, or call chart.install(countdown()); the countdown then shows on the next frame. Nothing throws, and the flag is kept as given.
market-status-missing
The chart was given marketStatus: true, but it has no marketStatus() plugin, so the legend shows no market phase or data delay badge. Logged once per page load. The option is on by default, so only an explicit true warns. Create the chart with marketStatus() (or builtins()) in its plugins, or call chart.install(marketStatus()); the badge then shows at once. Nothing throws, and the option is kept as given. chart.marketStatus() needs the plugin too: without it, it throws not-registered.
localization-missing
The chart was given a localization option, but it has no localization() plugin, so numbers, dates and the built-in text stay in the built-in English (chart.localization is englishLocalizer). Logged once per page load. Create the chart with localization() (or builtins()) in its plugins, or call chart.install(localization()); it then applies the option kept so far and fires localization:change. The option is still checked: an invalid locale tag, decimal separator, hour cycle or date format throws at the call.
stats-overlay-missing
The renderStats or renderStatsOverlay option is on, but the chart has no statsOverlay() plugin, so nothing is measured or shown: chart.frameStats stays null and frame:render never fires. Logged once per page load. Create the chart with statsOverlay() (or builtins()) in its plugins, or call chart.install(statsOverlay()).
source-markers-missing
The data source has markers, but the chart has no sourceMarkers() plugin, so it never asks for them: chart.sourceMarkers stays empty. Logged once per page load. Create the chart with sourceMarkers() (or builtins()) in its plugins, or call chart.install(sourceMarkers()); the markers of the shown symbol are then fetched.
lanes-missing
A primitive with lane() was attached, but the chart has no depthLane() plugin, which lays out lanes, so the primitive gets no space beside the price axis and its drawLane is not called. Logged once per page load. Create the chart with depthLane() (or builtins()) in its plugins, or call chart.install(depthLane()); the lanes already attached are then laid out.
shared-context-missing
The chart was created with gl: 'shared', but without the sharedContext() plugin in its plugins, so it draws through its own WebGL context and chart.options.gl reads 'own'. Logged once per page load. Create the chart with sharedContext() (or builtins()) in its plugins; installing it later changes nothing, since the context is chosen at creation.
data-source-missing
A React, Vue or Svelte Chart component got a dataSource prop, but its chart has no dataSource() plugin, so the source is not attached and nothing loads. The component does not throw (calling chart.setDataSource yourself does, with not-registered). Logged once per page load. Pass plugins: [dataSource()] (or builtins()) in the component's options, created once at module scope; plugins are read when the chart is created.
Error codes
Errors are thrown, passed to a rejected promise, or delivered through an event, as each entry says. cause holds the original error when there is one.
Development builds give each error an English message that names the call and the value at fault. Production builds leave the messages out, like the warnings: a ChartError's message is then its code (not-registered), with the same code, context and cause, and the plain Error, TypeError and RangeError thrown for invalid arguments have an empty message. Code loaded without a bundler counts as production here too. Branch on code, not on the message, and look the code up below. Two messages stay in production because the shell's compare button shows them: a symbol that is already compared, and compare on a chart without a data source.
webgl2-unavailable
createChart throws: the browser or device has no WebGL2, which the chart needs. Check isWebGL2Supported() first and show a fallback.
webgl-shader
createChart throws: a shader failed to compile or link, usually a GPU driver bug. Show a fallback; report it with the browser and GPU when it repeats.
webgl-restore-failed
context:restore-failed: the GPU context came back after a loss but could not be set up again. cause is the setup error. Destroy the chart and create a new one.
unknown-symbol
data:error, compare:error, or a rejected setSymbol: the data source's symbol threw, for any reason. That is an unknown symbol, but also a network or server failure; check cause, the source's error.
load-failed
data:error, compare:error, or a rejected setSymbol: the data source failed to load a symbol's first bars. cause is the source's error. Offer a retry (chart.reload()).
history-failed
data:error with kind: 'history': a page of older bars failed to load. cause is the source's error. Scrolling back asks again.
reset-failed
data:error with kind: 'reset': reloading bars after a source reset (onReset), a reconnect or chart.reload() failed. cause is the source's error.
adjustments-failed
data:warning: the data source's adjustments failed for a load (kind). The bars load anyway, unadjusted for that batch, and the chart notifies the user while the adjustment option is on. cause is the source's error. The next load of the symbol and interval asks again; chart.reload() retries at once.
markers-failed
sourcemarkers:error: the data source's markers failed. The bars are not affected. The chart asks again after retryIn ms (1 to 16 seconds, doubling); after five failures in a row retryIn is null and it waits for a reset of the shown bars (onReset), the marks or timeMarks option turned back on, or the next symbol or interval change. cause is the source's error.
invalid-interval
intervalSeconds and the built-in adapters throw: an interval string the chart cannot parse, such as '1x'. Use a number and a unit, such as '5m', '4h' or '1D'.
createOhlcvDataSource also throws it for an interval the exchange has no timeframe for. The chart avoids that by showing the nearest interval the symbol lists; check the symbol's intervals before asking for one directly.
invalid-drawings
drawings.load and parseSerialized: a payload that is not { version, drawings: [] }, or a version nothing can upgrade.
invalid-layout
loadLayout: a saved layout that is not an object with a version, or has a version nothing can upgrade.
listener-failed
The chart:error event: one of your event listeners threw. cause is what it threw. The other listeners and the frame still run.
primitive-failed
The chart:error event: a member of an attached primitive threw, on a time chart or a numeric chart. cause is what it threw, and context.member names the member, such as drawPlot or priceRange. The call counts as returning nothing. Other primitives, the series and the frame still draw, and a throwing detached does not stop detaching or destroy(). Only the first failure of each primitive is reported, so one that throws on every frame does not flood the listener. Without a chart:error listener, the error is logged to the console. An attached that throws is not caught: attachPrimitive rethrows it and the primitive is not attached.
destroyed
setSymbol rejects and compare and install throw after destroy(): the chart cannot load data any more. A numeric chart's attachPrimitive throws it too after destroy().
plugin-incompatible
chart.install(plugin) threw: the plugin's requires range does not include this core version (CORE_VERSION), or the range cannot be read. context holds plugin, version, requires and coreVersion. Upgrade core or install a plugin version made for it. See Plugins.
not-registered
Thrown at once by the call that needs the feature:
chart.setDataSource(source)on a chart without thedataSource()plugin, withcontext{ call: 'setDataSource', plugin: 'dataSource()' }. Detaching withsetDataSource(null)never throws.chart.serializeLayout()orchart.loadLayout()on a chart without thelayouts()plugin, withcontext{ call: 'serializeLayout', plugin: 'layouts()' }or{ call: 'loadLayout', plugin: 'layouts()' }.autosavereports the save's error through itsonError, andloadLastLayoutrejects with it when a saved layout exists.chart.referenceLineson a chart without thereferenceLines()plugin, withcontext{ call: 'referenceLines', plugin: 'referenceLines()' }. ThereferenceLinesoption never throwsnot-registered: without the plugin it is kept for a later install, and an unknown line or line style in it throws at the call, as with the plugin.chart.marketStatus()on a chart without themarketStatus()plugin, withcontext{ call: 'marketStatus', plugin: 'marketStatus()' }.chart.captureImage()on a chart without theimageCapture()plugin, withcontext{ call: 'captureImage', plugin: 'imageCapture()' }. A destroyed chart resolves tonullinstead.addHeatmap,addVolumeProfileoraddDepthLaneon a chart without theheatmap(),volumeProfile()ordepthLane()plugin.contextholds thecalland thepluginto add: create the chart with it inplugins(orbuiltins()), orchart.install(heatmap())later.chart.indicatorson a chart withoutindicators(), withcontext{ call: 'indicators', plugin: 'indicators()' }, and so do a plugin'sctx.registerIndicatorand the saved indicators of a layout, whichloadLayoutreports in itserrorsinstead of throwing.chart.compare()on a chart withoutcomparisons(), withcontext{ call: 'compare', plugin: 'comparisons()' }.chart.replayon a chart withoutreplay(), withcontext{ call: 'replay', plugin: 'replay()' }.chart.drawingson a chart without drawings (drawingTools()ordrawings()), andchart.annotationson one withoutannotations().contextis{ call: 'drawings', plugin: 'drawingTools()' }or{ call: 'annotations', plugin: 'annotations()' }. Trade fills and trading lines (annotations.setTrades,annotations.addTradeLineand the other fill and line calls) on a chart withouttrading(), withcontextsuch as{ call: 'annotations.setTrades', plugin: 'trading()' }, andtrading()installed on a chart without annotations, with{ call: 'trading()', plugin: 'annotations()' }. The same goes for what needs them: a plugin'sctx.registerDrawingTool,perSymbolDrawings, and the saved drawings of a layout, whichloadLayoutreports in itserrorsinstead of throwing.drawings.setToolordrawings.addwith a tool type the chart does not have.contextholds thecall, thetoolasked for and theavailabletypes, which the message lists too, so a misspelt type is easy to spot. A chart with no tools at all was created without thedrawingTools()plugin; a single tool can also be added withchart.drawings.register(tool).
See Opt-in features.