santifer/career-ops · error · Error
Unknown fixture state
Error message
Unknown fixture state: ${state} (have: ${states.join(', ') || 'none'}) What it means
assertKnownState() in seed-fixture.mjs throws this when a requested fixture state is not among the directories currently under the FIXTURES root (as returned by listStates(), basenames only). The guard doubles as a traversal defense: unknown names and path-like strings ('../x', 'state/../..') can never pass the membership check, so join(FIXTURES, state) can never escape the fixtures directory.
Solutions
- List the valid states (the error message includes them, or call listStates() yourself) and use one exactly.
- Fix the typo in the state option or test constant.
- If the state was renamed, update the caller to the new fixture directory name.
- If the message says 'have: none', the fixtures directory is missing or empty — restore it from the repo.
Example fix
// before
await seedFixture(dir, { state: 'aplied' }); // typo
// after
await seedFixture(dir, { state: 'applied' }); // must match a fixtures/<state> directory exactly Defensive patterns
Strategy: type-guard
Validate before calling
import { listStates } from './seed-fixture.mjs';
if (!listStates().includes(state)) {
throw new Error(`Invalid state '${state}'; valid: ${listStates().join(', ')}`);
} Type guard
const isKnownState = (state, states = listStates()) => states.includes(state);
Try / catch
try {
await seedFixture(dir, { state });
} catch (err) {
if (err.message.startsWith('Unknown fixture state')) {
console.error(`${err.message} — check for typos or a renamed fixture directory`);
} else throw err;
} Prevention
- Derive state names from listStates() instead of hardcoding strings in tests.
- Treat state as a closed enum: define it as a constant list kept in sync with the fixtures directory.
- Validate any user/env-supplied state value before passing it to seedFixture.
- Never embed path separators in a state name — exact basenames only.
When it happens
Trigger: seedFixture(targetDir, { state: 'no-such-state' }) or any state string that is not an exact basename of a directory in fixtures/ — including typos, stale state names after a fixture rename, or path-containing strings.
Common situations: Typo in the state option; test suite referencing a fixture state that was renamed/removed; passing a path fragment or env-supplied state value that was never validated upstream; running in a checkout where the fixtures directory is empty (message then shows 'have: none').
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- 4dayweek: invalid URL
- 4dayweek: URL must use HTTPS
- a 40-hex commit --sha is required
- apify: entry has invalid field_map. Each of title, url…
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/741188786bfa5547.
Report an issue: GitHub.
Appendix: source
Thrown at seed-fixture.mjs:62
// returns filesystem order, which varies).
//
// A checkout under test-fixtures/upgrade/ is excluded HERE, not only in
// walk(): this list is the state allowlist, and walk() starts AT the state
// directory, where the child-only guard cannot see it (the walk root is
// deliberately exempt). Leaving it in would make a whole second repository an
// allowlisted fixture state and seed it into the install under test (#3762).
return readdirSync(FIXTURES).sort()
.filter((n) => statSync(join(FIXTURES, n)).isDirectory() && !isNestedCheckout(join(FIXTURES, n)));
}
// Strict allowlist: a state must be one of the real fixture subdirectories.
// Membership in listStates() (basenames only) inherently rejects both unknown
// states and traversal strings ('../x', 'state/../..'), so no join() ever
// escapes FIXTURES.
function assertKnownState(state) {
const states = listStates();
if (!states.includes(state)) {
throw new Error(`Unknown fixture state: ${state} (have: ${states.join(', ') || 'none'})`);
}
}
export function seedFixture(targetDir, { state = DEFAULT_STATE } = {}) {
if (!existsSync(targetDir) || !statSync(targetDir).isDirectory()) throw new Error(`targetDir is not an existing directory: ${targetDir}`);
assertKnownState(state);
const src = join(FIXTURES, state);
// expected.json is harness metadata, not user data — never seed it.
const files = walk(src).filter((f) => f !== 'expected.json');
const manifest = {};
for (const f of files) {
const dest = join(targetDir, f);
mkdirSync(dirname(dest), { recursive: true });
cpSync(join(src, f), dest);
manifest[f] = createHash('sha256').update(readFileSync(dest)).digest('hex');
}
return { state, files, manifest };
}View on GitHub (pinned to aac998c7ed)