ant-design/ant-design · error · Error
${screenMax}<=${nextScreenMin} fails : !(${indexableToken[sc
Error message
${screenMax}<=${nextScreenMin} fails : !(${indexableToken[screenMax]}<=${indexableToken[nextScreenMin]}) What it means
validateBreakpoints() asserts that consecutive breakpoints chain correctly: screenXXMax <= nextScreenYYMin, where 'next' is the next entry in the reversed breakpoint array (i.e. the next smaller breakpoint). By default screenXXMax = nextScreen - 1 and nextScreenMin = nextScreen, so the invariant holds (575 <= 576). This is the third check in the loop (line 58), skipped for the last breakpoint. When it fails, one breakpoint's ceiling overlaps or exceeds the next breakpoint's floor, creating a gap or contradiction in the media-query lattice that responsive observers depend on.
Source
Thrown at components/_util/responsiveObserver.ts:59
throw new Error(
`${screenMin}<=${screen} fails : !(${indexableToken[screenMin]}<=${indexableToken[screen]})`,
);
}
if (i < revBreakpoints.length - 1) {
const screenMax = `screen${breakpointUpper}Max`;
if (!(indexableToken[screen] <= indexableToken[screenMax])) {
throw new Error(
`${screen}<=${screenMax} fails : !(${indexableToken[screen]}<=${indexableToken[screenMax]})`,
);
}
const nextBreakpointUpperMin = revBreakpoints[i + 1].toUpperCase();
const nextScreenMin = `screen${nextBreakpointUpperMin}Min`;
if (!(indexableToken[screenMax] <= indexableToken[nextScreenMin])) {
throw new Error(
`${screenMax}<=${nextScreenMin} fails : !(${indexableToken[screenMax]}<=${indexableToken[nextScreenMin]})`,
);
}
}
});
return token;
};
export const matchScreen = (screens: ScreenMap, screenSizes?: ScreenSizeMap) => {
if (!screenSizes) {
return;
}
for (const breakpoint of responsiveArray) {
if (screens[breakpoint] && screenSizes?.[breakpoint] !== undefined) {
return screenSizes[breakpoint];
}
}
};View on GitHub (pinned to 6455d91fab)
Solutions
- Read the error message for the exact pair, e.g. screenXSMax<=screenSMMin fails : !(1010<=576). Raise the second token (nextScreenMin) above the first (screenMax), or lower screenMax.
- When you increase screenXXMax, also increase the next breakpoint's screenYY / screenYYMin so that screenXXMax < screenYYMin.
- Override breakpoint tiers in contiguous groups rather than one tier at a time, so every boundary is consistent.
- Validate the full chain xs→xxxl before passing tokens to ConfigProvider: screenXSMax < screenSMMin, screenSMMax < screenMDMin, and so on for all six boundaries.
Example fix
// before — screenXSMax (1010) exceeds screenSMMin (576)
<ConfigProvider theme={{ token: { screenXS: 1000, screenXSMin: 1000, screenXSMax: 1010 } }}>
<App />
</ConfigProvider>
// after — raise the adjacent breakpoint to preserve the chain
<ConfigProvider theme={{ token: { screenXS: 1000, screenXSMin: 1000, screenXSMax: 1010, screenSM: 1024, screenSMMin: 1024 } }}>
<App />
</ConfigProvider> Defensive patterns
Strategy: validation
Validate before calling
import { responsiveArray } from 'antd/es/_util/responsiveObserver';
// Call before passing tokens to ConfigProvider
function assertBreakpointChainValid(token: Record<string, any>): void {
const rev = [...responsiveArray].reverse(); // xxxl, xxl, xl, lg, md, sm, xs
for (let i = 0; i < rev.length - 1; i++) {
const upper = rev[i].toUpperCase();
const nextUpper = rev[i + 1].toUpperCase();
const max = token[`screen${upper}Max`];
const nextMin = token[`screen${nextUpper}Min`];
if (typeof max === 'number' && typeof nextMin === 'number' && max > nextMin) {
throw new Error(
`Invalid token chain: screen${upper}Max (${max}) > screen${nextUpper}Min (${nextMin}). Raise the next breakpoint or lower screen${upper}Max.`,
);
}
}
}
// Usage:
// const myToken = { screenXS: 1000, screenXSMin: 1000, screenXSMax: 1010, screenSM: 1024, screenSMMin: 1024 };
// assertBreakpointChainValid(myToken);
// <ConfigProvider theme={{ token: myToken }}>... Type guard
import type { AliasToken } from 'antd/es/theme/interface/alias';
import { responsiveArray } from 'antd/es/_util/responsiveObserver';
function hasValidBreakpointChain(token: Partial<AliasToken>): boolean {
const rev = [...responsiveArray].reverse();
for (let i = 0; i < rev.length - 1; i++) {
const upper = rev[i].toUpperCase();
const nextUpper = rev[i + 1].toUpperCase();
const max = token[`screen${upper}Max` as keyof AliasToken] as number | undefined;
const nextMin = token[`screen${nextUpper}Min` as keyof AliasToken] as number | undefined;
if (max === undefined || nextMin === undefined) continue;
if (max > nextMin) return false;
}
return true;
} Try / catch
// Throws during React render — wrap in an Error Boundary, not a try/catch:
import React from 'react';
class BreakpointErrorBoundary extends React.Component<
{ children: React.ReactNode; fallback?: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(err: Error) {
if (err.message.includes('fails : !(')) {
console.error('Breakpoint chain validation failed:', err.message);
}
}
render() {
return this.state.hasError ? (this.props.fallback ?? null) : this.props.children;
}
}
// This only masks the crash; the responsive component will not render until
// the token chain is fixed. Prevention
- When raising any breakpoint tier, immediately check the boundary against both neighbors: screenXXMax must stay below the next smaller breakpoint's Min.
- Override breakpoint tiers in contiguous cascading groups — if you raise screenXL, also raise screenXXL (and its Max), and check that screenXLMax < screenXXLMin.
- Validate the entire xs→xxxl chain with a helper before passing tokens to ConfigProvider; check all six boundaries in one pass.
- Centralize breakpoint config in one typed, validated constant imported throughout the app.
- When translating from another design system's breakpoints, map the full ordered set at once and verify no overlaps or gaps exist.
When it happens
Trigger: Fires when a ConfigProvider theme.token override makes screenXXMax > nextScreenYYMin. Typical: { screenXS: 1000, screenXSMin: 1000, screenXSMax: 1010 } where screenSMMin stays at 576, producing screenXSMax<=screenSMMin fails : !(1010<=576). Also triggers when increasing any screenXXMax beyond the next breakpoint's Min without also raising that next breakpoint.
Common situations: Occurs when a developer overrides one breakpoint's Max (or all three values of one tier) but leaves adjacent breakpoints at defaults — the raised ceiling spills past the neighbor's floor. Also seen when porting a design-system spec that defines non-contiguous or overlapping breakpoints, or when incrementally adding token overrides without re-checking the full chain after each addition.
Related errors
- ${screenMin}<=${screen} fails : !(${indexableToken[screenMin
- ${screen}<=${screenMax} fails : !(${indexableToken[screen]}<
AI-assisted analysis of ant-design/ant-design@6455d91fab (2026-08-12).
Data as JSON: /api/errors/df8a76156f54d385.
Report an issue: GitHub.