santifer/career-ops · error · Error
Application answer state must be one of: ${[...VALID_STATES]
Error message
Application answer state must be one of: ${[...VALID_STATES].join(', ')} What it means
Validation in `normalizeState` (application-answers.mjs): the answer record's `state` field, after lowercasing and whitespace-normalizing, must be a member of `VALID_STATES` (defined as the set `['filled', 'submitted']`). Any other value — including common synonyms like 'draft', 'pending', 'done' — is rejected to keep the persisted state machine uniform.
Source
Thrown at application-answers.mjs:39
for (const key of keys) {
const value = object?.[key];
if (Array.isArray(value)) {
if (value.length > 0) return value;
continue;
}
if (value !== undefined && value !== null && String(value).trim()) return value;
}
return '';
}
function list(value) {
return Array.isArray(value) ? value : [];
}
function normalizeState(state) {
const normalized = inline(state || 'filled').toLowerCase();
if (!VALID_STATES.has(normalized)) {
throw new Error(`Application answer state must be one of: ${[...VALID_STATES].join(', ')}`);
}
return normalized;
}
function normalizeDate(date) {
return inline(date || new Date().toISOString().slice(0, 10));
}
function quoteBlock(value) {
const text = String(value ?? '').replace(/\r\n/g, '\n').trim();
if (!text) return '> Not recorded.';
return text.split('\n').map((line) => `> ${line}`).join('\n');
}
function qaLines(entries, { labelKeys, valueKeys, fallback }) {
if (entries.length === 0) return ['- None captured.'];
return entries.flatMap((entry, index) => {View on GitHub (pinned to 9b17a8ac97)
Solutions
- Use exactly one of `filled` or `submitted` (case-insensitive, surrounding whitespace tolerated).
- Map your upstream statuses onto these two before invoking the script: `Applied`/`Saved`/`Drafted` → `filled`; `Submitted`/`Sent` → `submitted`.
- Re-read the usage line: `--state filled|submitted`.
- If you genuinely need a third state, extend `VALID_STATES` and update the persistence format intentionally — don't smuggle new values through.
- Add a unit test listing accepted and rejected values.
Example fix
// before node application-answers.mjs --report r.md --input a.json --state submitted-to-portal // after node application-answers.mjs --report r.md --input a.json --state submitted
Defensive patterns
Strategy: validation
Validate before calling
const VALID = new Set(['filled', 'submitted']);
function normalizeState(s) {
const n = String(s || '').trim().toLowerCase();
if (!VALID.has(n)) throw new Error(`state must be filled|submitted, got: ${s}`);
return n;
} Type guard
function isAnswerState(s) {
return typeof s === 'string' &&
['filled', 'submitted'].includes(s.trim().toLowerCase());
} Prevention
- Map upstream statuses onto filled/submitted before invoking.
- Treat the state vocabulary as part of the schema — don't extend it ad hoc.
- Document the two accepted values wherever the CLI is referenced.
- Add tests enumerating accepted and rejected values.
When it happens
Trigger: Passing `--state draft`, `--state pending`, `--state DONE` (case ok but value wrong), `--state Applied`, or any non-`filled`/`submitted` token to the CLI; calling `normalizeState('saved')` programmatically; JSON input with `{ "state": "complete" }`.
Common situations: User types a synonym that 'feels' right; integration with another tool whose status vocabulary differs; copy-paste from a tracker that uses `Applied`/`Submitted`-style labels; migrating from an older schema that allowed free-form state.
Related errors
- Missing value for ${arg}
- decision must be one of: ${[...DECISIONS].join(', ')}
- --${name} is required
- --${name} must not contain tabs or newlines
- --${name} must be a percentage (e.g. 70 or 70%), got "${v}"
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/b9fd59f95fc44b9c.
Report an issue: GitHub.