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

  1. List the valid states (the error message includes them, or call listStates() yourself) and use one exactly.
  2. Fix the typo in the state option or test constant.
  3. If the state was renamed, update the caller to the new fixture directory name.
  4. 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

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


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)