{"record":{"id":"85a76ac7ea05cc20","repo":"affaan-m/ECC","slug":"spec-must-be-an-object","errorCode":null,"errorMessage":"spec must be an object","messagePattern":"spec must be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/master-agreement-generator/scripts/build-agreement.js","lineNumber":81,"sourceCode":"  return Array.from(rows, (row, rowIndex) => {\n    if (!Object.hasOwn(rows, rowIndex) || !Array.isArray(row) || row.length !== 6) {\n      throw new Error(`spec.schedule[${rowIndex}] must be a dense six-cell array`);\n    }\n    const cells = Array.from(row, (cell, cellIndex) => {\n      if (!Object.hasOwn(row, cellIndex) ||\n          !((typeof cell === 'string' && !/\\p{Surrogate}/u.test(cell)) ||\n            (typeof cell === 'number' && Number.isFinite(cell)))) {\n        throw new Error(`spec.schedule[${rowIndex}][${cellIndex}] must be valid Unicode text or a finite number`);\n      }\n      return encodeScheduleCell(cell);\n    });\n    return `| ${cells.join(' | ')} |`;\n  }).join('\\n');\n}\n\nfunction buildValues(spec, now) {\n  if (!spec || typeof spec !== 'object') {\n    throw new Error('spec must be an object');\n  }\n  for (const key of ['file', 'short', 'role']) {\n    if (typeof spec[key] !== 'string' || spec[key].trim() === '') {\n      throw new Error(`spec.${key} is required`);\n    }\n  }\n  // Reject path syntax on every host, including Windows paths supplied on POSIX.\n  if (/[<>:\"/\\\\|?*\\p{Cc}]/u.test(spec.file) ||\n      /[. ]$/.test(spec.file) ||\n      /^(con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³])(?:\\.|$)/i.test(spec.file)) {\n    throw new Error('spec.file must be a portable filename without path components or control characters');\n  }\n  const clauses = ROLE_CLAUSES[spec.role];\n  if (!clauses) {\n    throw new Error(`unknown role \"${spec.role}\"; expected one of ${Object.keys(ROLE_CLAUSES).join(', ')}`);\n  }\n  const cp = spec.short;\n  const fill = text => text.split('{cp}').join(cp);","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/master-agreement-generator/scripts/build-agreement.js#L63-L99","documentation":"buildValues() validates the spec object it uses to render the agreement. It throws this error when the caller passes null, undefined, or a non-object (string, array, number) instead of a spec. The library requires an object with file/short/role fields before any rendering happens.","triggerScenarios":"Calling values() or buildValues() with spec = null, spec = undefined, spec = 'my-spec', spec = [], or a JSON.parse() result that turned out to be a scalar.","commonSituations":"A spec JSON file parsed into a non-object (e.g. the file contains just a string), a config loader returning null on missing file, or passing command-line arguments positionally in the wrong order.","solutions":["Inspect what you passed as spec — log it or JSON.stringify it before calling buildValues.","Ensure the spec file on disk contains a JSON object ({...}), not a bare string or array.","Add an early guard in your caller: if (!spec || typeof spec !== 'object') handle before invoking the library.","If spec comes from JSON.parse of user input, wrap parsing in try/catch and validate shape with a schema (zod/ajv) first."],"exampleFix":"// before\nconst spec = JSON.parse(fs.readFileSync(specPath, 'utf8')); // could be null/string\nbuildValues(spec, now);\n// after\nconst parsed = JSON.parse(fs.readFileSync(specPath, 'utf8'));\nif (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n  throw new Error(`spec file ${specPath} does not contain a JSON object`);\n}\nbuildValues(parsed, now);","handlingStrategy":"validation","validationCode":"function isValidSpec(spec) {\n  return spec !== null && typeof spec === 'object' && !Array.isArray(spec);\n}\nif (!isValidSpec(mySpec)) throw new Error('spec must be a non-null object');","typeGuard":"function isSpecObject(v) {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  buildValues(spec, now);\n} catch (e) {\n  if (e.message === 'spec must be an object') {\n    console.error('Spec load failed: expected a JSON object');\n  } else throw e;\n}","preventionTips":["Always JSON.parse spec files inside try/catch and check the result is an object.","Validate spec shape with a schema (zod/ajv) at the boundary before calling library functions.","Never pass possibly-null config-loader results straight into buildValues."],"tags":["validation","argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}