mastra-ai/mastra · error
Dynamic memory factory returned empty value
Error message
Dynamic memory factory returned empty value
What it means
config.memory was provided as a dynamic factory function, but invoking it returned null/undefined (or a falsy value). The controller requires a concrete MastraMemory instance after resolution, so it throws to surface the misbehaving factory.
Source
Thrown at packages/core/src/agent-controller/agent-controller.ts:2286
return requestContext;
}
/**
* Resolve memory from config — handles both static instances and dynamic factory functions.
*/
private async resolveMemory(session: Session<TState>): Promise<MastraMemory> {
const mem = this.config.memory;
if (!mem) {
throw new Error('Memory is not configured on this AgentController');
}
if (typeof mem !== 'function') {
return mem;
}
const requestContext = await this.buildRequestContext(session);
const resolved = await Promise.resolve(mem({ requestContext }));
if (!resolved) {
throw new Error('Dynamic memory factory returned empty value');
}
return resolved;
}
// ===========================================================================
// Token Usage
// ===========================================================================
private async persistTokenUsage(session: Session<TState>): Promise<void> {
const threadId = session.thread.getId();
if (!threadId || !this.#resolveStorage()) return;
try {
const memoryStorage = await this.getMemoryStorage();
const thread = await memoryStorage.getThreadById({ threadId });
if (thread) {
await memoryStorage.saveThread({
thread: {View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure the factory always returns a MastraMemory instance on every code path
- Add explicit return statements / assertions inside the factory
- Throw inside the factory with a descriptive error when memory cannot be constructed, instead of returning undefined
Example fix
// before
memory: async ({ requestContext }) => {
if (requestContext.get('tenant')) return buildTenantMemory(requestContext.get('tenant'));
}
// after
memory: async ({ requestContext }) => {
const tenant = requestContext.get('tenant');
if (!tenant) throw new Error('No tenant in requestContext; cannot build memory');
return buildTenantMemory(tenant);
} Defensive patterns
Strategy: type-guard
Validate before calling
const resolved = await Promise.resolve(config.memory?.({ requestContext }));
if (!resolved) throw new Error('memory factory must return a MastraMemory'); Type guard
function isMemory(v: unknown): v is MastraMemory {
return !!v && typeof (v as MastraMemory).getThreads === 'function';
} Try / catch
try {
return await resolveMemory(session);
} catch (e) {
if (e instanceof Error && e.message.includes('Dynamic memory factory')) {
// fall back to a default memory or surface a config error
}
throw e;
} Prevention
- Type the factory return as MastraMemory (not optional) so TS flags missing returns
- Throw inside factories instead of returning undefined on failure paths
- Unit-test the memory factory for every requestContext branch
When it happens
Trigger: A config.memory async/sync factory that returns undefined — e.g. it conditionally returns nothing when a lookup fails, forgets its return statement, or awaits a function that resolves to void.
Common situations: Factories that branch on requestContext/env and hit an implicit undefined return; returning a promise-wrapped value incorrectly; switching from a static instance to a factory during a refactor.
Related errors
- Factory transition service is unavailable.
- ${setupError.message}. The sandbox stays usable: this setup
- sendStateSignal requires Mastra memory
- Storage is not configured on this AgentController
- Storage does not have a memory domain configured
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/26c4133bdaf09f5a.
Report an issue: GitHub.