{"record":{"id":"6066f752f32ef0cb","repo":"mermaid-js/mermaid","slug":"position-must-be-a-non-negative-integer-position","errorCode":null,"errorMessage":"Position must be a non-negative integer.${position}","messagePattern":"Position must be a non-negative integer\\.(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mermaid/src/diagrams/block/layout.ts","lineNumber":20,"sourceCode":"import type { Block } from './blockTypes.js';\nimport { log } from '../../logger.js';\nimport { getConfig } from '../../diagram-api/diagramAPI.js';\n\ninterface BlockPosition {\n  px: number;\n  py: number;\n}\n\nexport function calculateBlockPosition(columns: number, position: number): BlockPosition {\n  // log.debug('calculateBlockPosition abc89', columns, position);\n  // Ensure that columns is a positive integer\n  if (columns === 0 || !Number.isInteger(columns)) {\n    throw new Error('Columns must be an integer !== 0.');\n  }\n\n  // Ensure that position is a non-negative integer\n  if (position < 0 || !Number.isInteger(position)) {\n    throw new Error('Position must be a non-negative integer.' + position);\n  }\n\n  if (columns < 0) {\n    // Auto columns is set\n    return { px: position, py: 0 };\n  }\n  if (columns === 1) {\n    // Auto columns is set\n    return { px: 0, py: position };\n  }\n  // Calculate posX and posY\n  const px = position % columns;\n  const py = Math.floor(position / columns);\n  // log.debug('calculateBlockPosition abc89', columns, position, '=> (', px, py, ')');\n  return { px, py };\n}\n\nconst getMaxChildSize = (block: Block) => {","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/mermaid-js/mermaid/blob/d93e9c88c01a599c062ee6a3f1462e3558ac6b90/packages/mermaid/src/diagrams/block/layout.ts#L2-L38","documentation":"Thrown by calculateBlockPosition when `position` is negative or not an integer. Position is the zero-based index of a block within its parent's grid; negative indices and fractional positions have no meaning in the grid math. Note the message concatenates the raw position value onto the string with no separator, so the number appears directly appended.","triggerScenarios":"Calling calculateBlockPosition(cols, -1) or calculateBlockPosition(cols, 1.5). Internally position is derived from iteration order and widthInColumns accounting, so a negative value usually signals an underflow in that accounting.","commonSituations":"Off-by-one errors in computed positions; integer underflow when subtracting widthInColumns; floating-point positions from division that should have been floored.","solutions":["Ensure position is >= 0 and an integer before calling.","Clamp computed positions to 0 and floor/round any fractional result."],"exampleFix":"// before\ncalculateBlockPosition(3, -1);\ncalculateBlockPosition(3, 1.5);\n// after\ncalculateBlockPosition(3, Math.max(0, Math.floor(rawIndex)));","handlingStrategy":"validation","validationCode":"function calculateBlockPositionSafe(columns, position) {\n  if (position < 0 || !Number.isInteger(position)) {\n    throw new Error(`position must be a non-negative integer; got ${position}`);\n  }\n  return calculateBlockPosition(columns, position);\n}","typeGuard":"const isValidPosition = (p) => Number.isInteger(p) && p >= 0;","tryCatchPattern":null,"preventionTips":["Clamp computed positions to >= 0.","Floor fractional positions before passing them in."],"tags":["block","layout","validation","grid"],"backgroundTag":null,"analyzedSha":"d93e9c88c01a599c062ee6a3f1462e3558ac6b90","analyzedAt":"2026-08-12T06:23:11.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}