affaan-m/ECC · error · Error

spec.schedule[ ][ ] must be valid Unicode text or a finite…

Error message

spec.schedule[${rowIndex}][${cellIndex}] must be valid Unicode text or a finite number

What it means

Each schedule cell must be either a string with no unpaired surrogate code points (checked via /\p{Surrogate}/u) or a finite number. Cells that are holes (missing own property), booleans, null, objects, NaN/Infinity, or strings containing lone surrogates are rejected with a message pinpointing the row and cell index.

Solutions

  1. Coerce numeric cells with Number.isFinite checks and replace NaN/Infinity with 0 or a valid value.
  2. Fix lone surrogates: use Array.from(str) instead of str.slice on code-unit boundaries when trimming emoji.
  3. Replace null/boolean/object cells with strings ('yes'/'no', String(value)) or numbers.
  4. Ensure the cell exists (assign '' rather than delete) so Object.hasOwn passes.
  5. Pre-validate cells: typeof c === 'string' && !/\p{Surrogate}/u.test(c) || typeof c === 'number' && Number.isFinite(c).

Example fix

// before
row[3] = note.slice(0, 10);            // may split an emoji -> lone surrogate
// after
row[3] = Array.from(note).slice(0, 10).join(''); // code-point-safe truncation
Defensive patterns

Strategy: validation

Validate before calling

function isValidCell(c) {
  return Object.hasOwn(arguments, 0) &&
    ((typeof c === 'string' && !/\p{Surrogate}/u.test(c)) ||
     (typeof c === 'number' && Number.isFinite(c)));
}
// sanitize before build:
cells = cells.map(c => Number.isFinite(c) ? c : (c == null ? '' : String(c)));

Type guard

const isValidCell = (c) =>
  (typeof c === 'string' && !/\p{Surrogate}/u.test(c)) ||
  (typeof c === 'number' && Number.isFinite(c));

Try / catch

try {
  buildAgreement(spec);
} catch (e) {
  const m = e.message.match(/spec\.schedule\[(\d+)\]\[(\d+)\]/);
  if (m) {
    const [i, j] = [Number(m[1]), Number(m[2])];
    spec.schedule[i][j] = sanitizeCell(spec.schedule[i][j]);
    return buildAgreement(spec);
  }
  throw e;
}

Prevention

When it happens

Trigger: spec.schedule[0][2] = true; a cell set to NaN/Infinity from a bad computation; a cell containing a lone surrogate (e.g. '\uD800' from truncated slicing of an emoji string); a cell index deleted (Object.hasOwn fails); nested objects/arrays in a cell.

Common situations: Numeric columns computed with parseFloat returning NaN; string slicing cutting a multi-byte emoji in half; JSON round-trip turning undefined cells into holes; pasting rich data (objects) into a cell meant for plain text.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

}

function renderScheduleRows(rows) {
  if (rows === undefined) {
    return EMPTY_SCHEDULE_ROW;
  }
  if (!Array.isArray(rows)) {
    throw new Error('spec.schedule must be an array of six-cell rows');
  }
  if (rows.length === 0) return EMPTY_SCHEDULE_ROW;
  return Array.from(rows, (row, rowIndex) => {
    if (!Object.hasOwn(rows, rowIndex) || !Array.isArray(row) || row.length !== 6) {
      throw new Error(`spec.schedule[${rowIndex}] must be a dense six-cell array`);
    }
    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) ||

View on GitHub (pinned to 8321021c54)