toeverything/AFFiNE · error · Error
Path data ended short
Error message
Path data ended short
What it means
parsePath() converts an SVG path 'd' string into Segment objects. 'Path data ended short' is thrown when a command requires more numeric parameters than remain in the token stream — the loop guard `index + paramsCount < tokens.length` fails. Each command's required count is defined in the PARAMS table (M/L=2, C=6, Q/S=4, H/V=1, A=7, Z=0).
Source
Thrown at blocksuite/affine/blocks/surface/src/utils/path-data-parser/parser.ts:119
params[params.length] = +numbeToken.text;
} else {
throw new Error(
'Param not a number: ' + mode + ',' + numbeToken.text
);
}
}
if (typeof PARAMS[mode] === 'number') {
const segment: Segment = { key: mode, data: params };
segments.push(segment);
index += paramsCount;
token = tokens[index];
if (mode === 'M') mode = 'L';
if (mode === 'm') mode = 'l';
} else {
throw new Error('Bad segment: ' + mode);
}
} else {
throw new Error('Path data ended short');
}
}
return segments;
}
export function serialize(segments: Segment[]): string {
const tokens: (string | number)[] = [];
for (const { key, data } of segments) {
tokens.push(key);
switch (key) {
case 'C':
case 'c':
tokens.push(
data[0],
`${data[1]},`,
data[2],
`${data[3]},`,
data[4],View on GitHub (pinned to 26c515e050)
Solutions
- Verify every command is followed by exactly the count of numbers its PARAMS entry requires (A/a=7, C/c=6, Q/q/S/s=4, M/m/L/l=2, H/h/V/v/T/t=1, Z/z=0).
- If constructing paths programmatically, use the module's own serialize() rather than manual string concatenation.
- Run the path string through an SVG path linter/validator before passing it to parsePath().
Example fix
// before
parsePath('M 10 20 C'); // C needs 6 numbers
// after
parsePath('M 10 20 C 30 40 50 60 70 80'); Defensive patterns
Strategy: validation
Validate before calling
function paramCountsOk(d: string): boolean {
const PARAMS: Record<string, number> = { A:7,a:7,C:6,c:6,H:1,h:1,L:2,l:2,M:2,m:2,Q:4,q:4,S:4,s:4,T:2,t:2,V:1,v:1,Z:0,z:0 };
const tokens = (d.match(/[aAcChHlLmMqQsStTvVzZ]|-?\d*\.?\d+(?:[eE][-+]?\d+)?/g) ?? []);
let i = 0, mode = 'M';
while (i < tokens.length) {
if (/[a-zA-Z]/.test(tokens[i])) mode = tokens[i++];
const need = PARAMS[mode];
if (need === undefined) return false;
for (let k = 0; k < need; k++) { if (i >= tokens.length || /a-zA-Z/.test(tokens[i])) return false; i++; }
}
return true;
} Try / catch
try {
const segments = parsePath(d);
} catch (e) {
if (e instanceof Error && e.message === 'Path data ended short') {
// sanitize or skip this path
} else throw e;
} Prevention
- Round-trip paths through serialize() from the same module instead of hand-building strings
- Lint persisted SVG path data on save
When it happens
Trigger: Calling parsePath() with a truncated or malformed path string, e.g. 'M 10 20 C' (C expects 6 numbers, none follow), 'L 5' (L expects 2), or a string that ends mid-segment after a command token. Also triggered when a number token is missing between commands.
Common situations: Hand-authored or pasted SVG path data with a typo; path strings truncated during serialization, clipboard transfer, or URL encoding; dynamically built path strings via string concatenation that drop trailing coordinates.
Related errors
- Param not a number: ${mode},${numbeToken.text}
- Bad segment: ${mode}
- ParsingError
- Invalid duration string unit ${ch}
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/46bb0fcb907dae40.
Report an issue: GitHub.