affaan-m/ECC · error · Error

spec. is required

Error message

spec.${key} is required

What it means

After confirming spec is an object, buildValues() requires the fields file, short, and role to be non-empty trimmed strings. It throws templated 'spec.<key> is required' when any of them is missing, not a string, or whitespace-only. These fields drive the output filename, short citation form, and clause selection.

Solutions

  1. Read the error message: it names the exact missing key (e.g. spec.role is required).
  2. Add that key to your spec with a non-empty string value.
  3. Trim whitespace-only values — a string of spaces still fails.
  4. Validate the whole spec up front with a schema so all missing fields are reported at once instead of one at a time.

Example fix

// before
const spec = { file: 'NDA', short: '' };
// after
const spec = { file: 'NDA', short: 'NDA-2026', role: 'consultant' };
Defensive patterns

Strategy: validation

Validate before calling

const REQUIRED = ['file', 'short', 'role'];
const missing = REQUIRED.filter(k => typeof spec?.[k] !== 'string' || spec[k].trim() === '');
if (missing.length) throw new Error(`spec missing: ${missing.join(', ')}`);

Type guard

function hasRequiredSpecFields(spec) {
  return typeof spec === 'object' && spec !== null &&
    ['file', 'short', 'role'].every(k => typeof spec[k] === 'string' && spec[k].trim() !== '');
}

Try / catch

try {
  buildValues(spec, now);
} catch (e) {
  if (/^spec\.[a-z]+ is required$/.test(e.message)) {
    console.error(`Incomplete spec: ${e.message}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling values()/buildValues() with a spec object missing e.g. role, or where spec.short is '' or ' ', or where the field is a number/boolean instead of a string.

Common situations: Hand-edited spec JSON with a typo'd field name (e.g. 'filename' instead of 'file'), a form/CLI that allows blank inputs, or a partial spec object constructed programmatically with defaults left undefined.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/2c268751fd95bf7f. Report an issue: GitHub.

Appendix: source

Thrown at skills/master-agreement-generator/scripts/build-agreement.js:85

    const cells = Array.from(row, (cell, cellIndex) => {
      if (!Object.hasOwn(row, cellIndex) ||
          !((typeof cell === 'string' && !/\p{Surrogate}/u.test(cell)) ||
            (typeof cell === 'number' && Number.isFinite(cell)))) {
        throw new Error(`spec.schedule[${rowIndex}][${cellIndex}] must be valid Unicode text or a finite number`);
      }
      return encodeScheduleCell(cell);
    });
    return `| ${cells.join(' | ')} |`;
  }).join('\n');
}

function buildValues(spec, now) {
  if (!spec || typeof spec !== 'object') {
    throw new Error('spec must be an object');
  }
  for (const key of ['file', 'short', 'role']) {
    if (typeof spec[key] !== 'string' || spec[key].trim() === '') {
      throw new Error(`spec.${key} is required`);
    }
  }
  // Reject path syntax on every host, including Windows paths supplied on POSIX.
  if (/[<>:"/\\|?*\p{Cc}]/u.test(spec.file) ||
      /[. ]$/.test(spec.file) ||
      /^(con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³])(?:\.|$)/i.test(spec.file)) {
    throw new Error('spec.file must be a portable filename without path components or control characters');
  }
  const clauses = ROLE_CLAUSES[spec.role];
  if (!clauses) {
    throw new Error(`unknown role "${spec.role}"; expected one of ${Object.keys(ROLE_CLAUSES).join(', ')}`);
  }
  const cp = spec.short;
  const fill = text => text.split('{cp}').join(cp);
  const supplement = typeof spec.supplement === 'string' && spec.supplement.trim() ? `${spec.supplement.trim()}; ` : '';

  return {
    FEE_TITLE: clauses.title,

View on GitHub (pinned to 8321021c54)