chartjs/Chart.js · error · Error
Cannot determine type of '${id}' axis. Please provide 'axis'
Error message
Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option. What it means
determineAxis() tries to infer the axis ('x', 'y', or 'r') for a scale id by checking, in order: whether the id itself is 'x'/'y'/'r', the scale config's `axis` property, the `position` property (top/bottom -> x, left/right -> y), and finally a single-letter prefix of the id. If none of these yield an axis, Chart.js cannot know how to place or orient the scale and throws this error during config merging (mergeScaleConfig), before the chart renders.
Source
Thrown at src/core/core.config.js:52
}
if (position === 'left' || position === 'right') {
return 'y';
}
}
export function determineAxis(id, ...scaleOptions) {
if (idMatchesAxis(id)) {
return id;
}
for (const opts of scaleOptions) {
const axis = opts.axis
|| axisFromPosition(opts.position)
|| id.length > 1 && idMatchesAxis(id[0].toLowerCase());
if (axis) {
return axis;
}
}
throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);
}
function getAxisFromDataset(id, axis, dataset) {
if (dataset[axis + 'AxisID'] === id) {
return {axis};
}
}
function retrieveAxisFromDatasets(id, config) {
if (config.data && config.data.datasets) {
const boundDs = config.data.datasets.filter((d) => d.xAxisID === id || d.yAxisID === id);
if (boundDs.length) {
return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);
}
}
return {};
}
View on GitHub (pinned to cb02e1d207)
Solutions
- Add an explicit `position` to the scale: scales: { myScale: { type: 'linear', position: 'left' } }.
- Or set the `axis` property directly: scales: { myScale: { type: 'linear', axis: 'y' } }.
- Or name the scale id with a single leading axis letter it should map to (id 'y' / 'x' / 'r' match directly; a 2+ char id whose first char lowercased is x/y/r is accepted as a fallback).
- Audit every custom scale id in options.scales and confirm each has either position or axis set.
Example fix
// before
scales: {
temp: { type: 'linear' }
}
// after
scales: {
temp: { type: 'linear', position: 'left' }
} Defensive patterns
Strategy: validation
Validate before calling
// Validate every scale config has a determinable axis before constructing the chart.
function validateScales(scales) {
const known = new Set(['x', 'y', 'r']);
const posToAxis = { top: 'x', bottom: 'x', left: 'y', right: 'y' };
for (const [id, cfg] of Object.entries(scales ?? {})) {
const c = cfg || {};
const axis = known.has(id) ? id
: c.axis
|| posToAxis[c.position]
|| (id.length > 1 && known.has(id[0].toLowerCase()) ? id[0].toLowerCase() : null);
if (!axis) {
throw new Error(`Scale '${id}' needs 'axis' or 'position' (top|bottom|left|right).`);
}
}
}
validateScales(config.options?.scales); Type guard
// Narrow scale options to a shape that always carries axis info.
type PositionedScale = { type?: string; axis?: 'x' | 'y' | 'r'; position?: 'top' | 'bottom' | 'left' | 'right' };
function isPositionedScale(s: unknown): s is PositionedScale {
if (!s || typeof s !== 'object') return false;
const o = s as PositionedScale;
return Boolean(o.axis || ['top', 'bottom', 'left', 'right'].includes(o.position as string));
} Prevention
- Adopt a lint rule or wrapper that rejects scale configs lacking position/axis for custom ids.
- Prefer standard ids 'x'/'y'/'r' for primary axes so inference works without extra config.
- When refactoring scale ids, run a quick render test to catch missing axis inference.
- Keep a config schema (JSON Schema / zod) for chart options in shared libraries.
When it happens
Trigger: Declaring a scale whose id is not 'x'/'y'/'r' (e.g. a multi-char id like 'myScale' or 'temperature') and omitting both the `axis` and `position` options on that scale config; or passing a scale config object that is missing both keys. Thrown at config build time inside Config/mergeScaleConfig -> determineAxis.
Common situations: Renaming scale ids for readability (e.g. 'yTemp') without adding position; copying a multi-axis config snippet that used custom ids and dropping the position field; v3->v4 migration where previously inferred axes now require explicit `position`; SSR or unit-test setups feeding minimal scale objects.
Related errors
- This method is not implemented: Check that a complete date a
- No dataset found at index ${datasetIndex}
- "${id}" is not a registered ${type}.
- class does not have id: ${item}
- Recursion detected: ${Array.from(_stack).join('->')}->${prop
AI-assisted analysis of chartjs/Chart.js@cb02e1d207 (2026-08-12).
Data as JSON: /api/errors/323cffc12a8bcfdf.
Report an issue: GitHub.