n8n-io/n8n · error · Error
Observational memory requires a storage backend that…
Error message
Observational memory requires a storage backend that implements BuiltObservationLogStore.
What it means
Thrown from resolveMemoryConfigDefaults when observationalMemory is enabled but the configured storage backend (config.memory) does not implement BuiltObservationLogStore. The store capability is detected structurally via hasObservationLogStore, which checks for the six observation-log methods (appendObservationLogEntries, getActiveObservationLog, getObservationLog, dropObservationLogEntries, supersedeObservationLogEntries, applyObservationLogReflection).
Solutions
- Use the default InMemoryMemory (omit .storage() or pass 'memory') — it implements both BuiltObservationLogStore and BuiltEpisodicMemoryStore.
- Extend your custom backend to implement all six BuiltObservationLogStore methods (and the task-lock methods when needed).
- If your backend cannot support observational memory, do not call .observationalMemory() on that agent's Memory builder.
Example fix
// before
const mem = new Memory().storage(customBackend).observationalMemory({});
// after
const mem = new Memory().storage('memory').observationalMemory({}); Defensive patterns
Strategy: type-guard
Validate before calling
import { hasObservationLogStore } from '@n8n/agents/runtime/memory/observation-log-store';
if (config.observationalMemory && !hasObservationLogStore(config.memory)) {
throw new Error('observational memory needs a BuiltObservationLogStore backend');
} Type guard
import { hasObservationLogStore } from '@n8n/agents/runtime/memory/observation-log-store';
function supportsObservationalMemory(m: BuiltMemory): boolean {
return hasObservationLogStore(m);
} Prevention
- Default to .storage('memory') unless you have a specific reason to bring a custom backend.
- If you implement a custom backend, have it declare which Built*Store interfaces it implements and unit-test for them.
When it happens
Trigger: Passing a custom BuiltMemory to Memory.storage(customBackend), enabling .observationalMemory({...}), then triggering resolveMemoryConfigDefaults (typically through Agent build) — and the custom backend omits any of the observation-log methods.
Common situations: Bringing your own persistent backend that only implements thread/message storage; partial implementation of BuiltMemory; upgrading @n8n/agents where observational memory was added later than your backend was written.
Related errors
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0d1e475fd36ba572.
Report an issue: GitHub.
Appendix: source
Thrown at packages/@n8n/agents/src/sdk/memory.ts:103
}
export function resolveMemoryConfigDefaults(
config: MemoryConfig,
options: ResolveMemoryConfigDefaultsOptions,
): MemoryConfig {
const episodicMemory = isEpisodicMemoryEnabled(config.episodicMemory)
? resolveEpisodicMemoryConfig(config.episodicMemory, options)
: config.episodicMemory;
if (!config.observationalMemory) {
return normalizeMemoryConfig({
...config,
episodicMemory,
});
}
if (!hasObservationLogStore(config.memory)) {
throw new Error(
'Observational memory requires a storage backend that implements BuiltObservationLogStore.',
);
}
const observationalMemoryConfig =
config.observationLog?.renderTokenBudget !== undefined &&
config.observationalMemory.renderTokenBudget === undefined
? {
...config.observationalMemory,
renderTokenBudget: config.observationLog.renderTokenBudget,
}
: config.observationalMemory;
const observationalMemory = resolveObservationalMemoryConfig(observationalMemoryConfig, options);
return normalizeMemoryConfig({
...config,
memory: config.memory,
observationalMemory,View on GitHub (pinned to 5ac6606e81)