affaan-m/ECC · error · ReplayError
replay.no_store
replay.no_store
Error message
a FixtureStore is required
What it means
createReplayer throws ReplayError('replay.no_store') when options.store is falsy. Both record and replay modes need a FixtureStore: record writes fixtures into it and replay reads them. The constructor requires it unconditionally so a misconfigured suite cannot appear to pass while actually skipping persistence.
Solutions
- Construct and pass a FixtureStore: createReplayer(tools, { store: new FixtureStore('fixtures/eval'), mode }).
- Verify the store-producing helper actually returns a FixtureStore instance and not undefined/null (log it before createReplayer).
- Make the fixture directory a required, validated config value so it cannot silently become undefined.
- If the store depends on an optional feature, fail earlier with a clear message instead of letting the spread drop the option.
Example fix
// before
const replayer = createReplayer(tools, { mode: 'record' });
// after
const store = new FixtureStore(path.join(__dirname, 'fixtures'));
const replayer = createReplayer(tools, { mode: 'record', store }); Defensive patterns
Strategy: validation
Validate before calling
const store = new FixtureStore(process.env.FIXTURE_DIR || path.join(__dirname, 'fixtures'));
if (!(store instanceof FixtureStore)) throw new Error('fixture store not initialized');
createReplayer(tools, { mode, store }); Type guard
function isFixtureStore(v) {
return v instanceof FixtureStore;
} Try / catch
try {
return createReplayer(tools, { mode, store });
} catch (e) {
if (e instanceof ReplayError && e.code === 'replay.no_store') {
throw new Error('FixtureStore must be constructed and passed as options.store');
}
throw e;
} Prevention
- Always construct the FixtureStore next to createReplayer in the same setup function
- Make the fixture directory a validated required config value
- Avoid conditional spreads that can silently drop options.store
- Write one shared suite-bootstrap helper so the store is never forgotten
When it happens
Trigger: Calling createReplayer(tools) with no options, or with options.store undefined/null — e.g. the FixtureStore was never constructed, a factory function returning null on failure, or a conditional `...(useStore && { store })` spread evaluating false.
Common situations: Copy-pasting an example that omitted the store; refactoring away the fixture directory constant so `new FixtureStore(dir)` is never called; a config loader returning null when a path is missing; forgetting that the store argument is required, not optional.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- createPlanCanvasServer requires a session store
- replay.bad_mode
- tool.fixture_corrupt
- tool.fixture_mismatch
- tool.fixture_missing
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/d35667cd15b03bb2.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/eval-harness/replay.js:98
throw new ReplayError('tool.fixture_mismatch', `fixture ${key.slice(0, 16)} response hash does not match its content`, { tool, key });
}
return record;
}
}
/**
* tools: { name: { effect_class, determinism: 'deterministic'|'nondeterministic', impl(args) } }
* options: { mode: 'record'|'replay', store: FixtureStore, maxEffectClass: 'SE2', onCall(entry) }
*/
function createReplayer(tools, options = {}) {
const mode = options.mode || 'replay';
const store = options.store;
const maxRank = envelope.effectRank(options.maxEffectClass || 'SE2');
if (!['record', 'replay'].includes(mode)) {
throw new ReplayError('replay.bad_mode', `mode must be record or replay, got ${mode}`);
}
if (!store) {
throw new ReplayError('replay.no_store', 'a FixtureStore is required');
}
for (const [name, tool] of Object.entries(tools)) {
if (!envelope.EFFECT_CLASSES.includes(tool.effect_class)) {
throw new ReplayError('replay.bad_declaration', `tool ${name} must declare an effect_class`);
}
if (!['deterministic', 'nondeterministic'].includes(tool.determinism)) {
throw new ReplayError('replay.bad_declaration', `tool ${name} must declare determinism`);
}
}
const calls = [];
const emit = (entry) => {
calls.push(entry);
if (typeof options.onCall === 'function') {
options.onCall(entry);
}
};
View on GitHub (pinned to 8321021c54)