{"record":{"id":"6491fe5e2446a3ea","repo":"jackwener/OpenCLI","slug":"coords-must-be-in-x-y-format-e-g-1-2","errorCode":null,"errorMessage":"coords must be in \"x,y\" format (e.g. \"1,2\")","messagePattern":"coords must be in \"x,y\" format \\(e\\.g\\. \"1,2\"\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/geogebra/utils.js","lineNumber":53,"sourceCode":"  if (parts.length < min || parts.length > max) {\n    throw new ArgumentError(`${label} must contain ${min === max ? min : `${min}-${max}`} comma-separated labels`);\n  }\n  return parts.map((part, idx) => normalizeLabel(part, `${label}[${idx + 1}]`));\n}\n\nexport function normalizeNumber(value, label, { defaultValue, positive = false } = {}) {\n  const raw = value == null || value === '' ? defaultValue : value;\n  const number = Number(raw);\n  if (!Number.isFinite(number) || (positive && number <= 0)) {\n    throw new ArgumentError(`${label} must be a ${positive ? 'positive ' : ''}finite number`);\n  }\n  return number;\n}\n\nexport function normalizeCoords(value) {\n  const parts = String(value ?? '').split(',').map(s => s.trim());\n  if (parts.length !== 2) {\n    throw new ArgumentError('coords must be in \"x,y\" format (e.g. \"1,2\")');\n  }\n  return parts.map((part, idx) => normalizeNumber(part, idx === 0 ? 'x' : 'y'));\n}\n\nexport function requireGgbSuccess(result, message) {\n  if (!isPlainObject(result)) {\n    throw new CommandExecutionError(`${message}: malformed GeoGebra result`);\n  }\n  if (!result.ok) {\n    throw new CommandExecutionError(result.error || message);\n  }\n  return result;\n}\n\n/**\n * Navigate to GeoGebra Geometry (if not already there) and wait for\n * the ggbApplet API to become available.\n */","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/geogebra/utils.js#L35-L71","documentation":"normalizeCoords() splits a coordinate string on commas and requires exactly two trimmed parts, which it then forwards to normalizeNumber as x and y. It throws ArgumentError when the input does not have exactly two comma-separated components, because GeoGebra point placement needs both an x and a y value.","triggerScenarios":"Calling any point-creating tool with coords like '1' (missing y), '1,2,3' (extra component), '1;2' (wrong separator), or an empty string — parts.length !== 2 triggers the throw.","commonSituations":"Users typing coordinates with a space+comma only ('1 ,'), using locale decimal commas ('1,5,2,5' for two decimals), or passing a JSON array instead of the documented 'x,y' string.","solutions":["Pass coordinates exactly as 'x,y' with a comma separator and no extra components (e.g. '1,2').","Use '.' as the decimal separator: '1.5,2.5' not '1,5 2,5'.","If data is an array or object, join it first: [x, y].join(',').","Validate the format before calling: /^\\s*-?\\d+(\\.\\d+)?\\s*,\\s*-?\\d+(\\.\\d+)?\\s*$/.test(coords)."],"exampleFix":"// before\nawait placePoint({ coords: [1, 2] });\n// after\nawait placePoint({ coords: '1,2' });","handlingStrategy":"validation","validationCode":"const COORD_RE = /^\\s*-?\\d+(\\.\\d+)?\\s*,\\s*-?\\d+(\\.\\d+)?\\s*$/;\nif (!COORD_RE.test(coords)) throw new Error('coords must be \"x,y\", e.g. \"1,2\"');","typeGuard":"null","tryCatchPattern":"try { await placePoint({ coords }); } catch (e) { if (String(e.message).includes('x,y')) { console.error('Use format \"1,2\" with a comma and decimal points, not commas'); } else throw e; }","preventionTips":["Always build coords as `${x},${y}` from numbers, never raw user strings.","Use '.' for decimals; convert locale-formatted input first.","Reject arrays/objects at the boundary and join them into the string format."],"tags":["argument-validation","input-format","cli"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}