mastra-ai/mastra · error · Error
RunScope: missing required slot ${sym.toString()}
Error message
RunScope: missing required slot ${sym.toString()} What it means
RunScope stores values under symbol keys; getOrThrow<T>(key) requires the slot to have been set and throws a plain Error naming the missing symbol if it was never populated. It is used to guarantee that messageList, stored, and loopOptions are present before dependent code runs — a slot may be read only after some upstream code called set().
Source
Thrown at packages/core/src/mastra/run-scope.ts:66
getOrThrow<T>(key: RunScopeKey<T>): T;
set<T>(key: RunScopeKey<T>, value: T): void;
delete<T>(key: RunScopeKey<T>): void;
has<T>(key: RunScopeKey<T>): boolean;
/** Test-only: number of slots currently populated. */
readonly size: number;
}
class MapRunScope implements RunScope {
readonly #slots = new Map<symbol, unknown>();
get<T>(key: RunScopeKey<T>): T | undefined {
return this.#slots.get(key as unknown as symbol) as T | undefined;
}
getOrThrow<T>(key: RunScopeKey<T>): T {
const sym = key as unknown as symbol;
if (!this.#slots.has(sym)) {
throw new Error(`RunScope: missing required slot ${sym.toString()}`);
}
return this.#slots.get(sym) as T;
}
set<T>(key: RunScopeKey<T>, value: T): void {
this.#slots.set(key as unknown as symbol, value);
}
delete<T>(key: RunScopeKey<T>): void {
this.#slots.delete(key as unknown as symbol);
}
has<T>(key: RunScopeKey<T>): boolean {
return this.#slots.has(key as unknown as symbol);
}
get size(): number {
return this.#slots.size;View on GitHub (pinned to 75dd419e61)
Solutions
- Use the optional get(key) accessor when the slot may legitimately be absent, and handle undefined.
- Ensure the code that sets the slot (scope.set(key, value)) runs before any getOrThrow on that key, in the same request/scope instance.
- Pass the same RunScope instance through the call chain instead of constructing a new one.
- Wrap getOrThrow in try/catch if absence is expected in some code paths, and fall back to constructing the value.
Example fix
// before
const list = scope.getOrThrow(RunScopeKeys.messageList); // may throw if unset
// after
const list = scope.get(RunScopeKeys.messageList);
if (!list) throw new Error('messageList not yet initialized'); // or initialize it before this point Defensive patterns
Strategy: fallback
Validate before calling
if (!scope.has?.(RunScopeKeys.messageList)) {
throw new Error('messageList slot must be set before reading it from RunScope');
} Try / catch
let messageList;
try {
messageList = scope.getOrThrow(RunScopeKeys.messageList);
} catch (e) {
if (e instanceof Error && e.message.startsWith('RunScope: missing required slot')) {
messageList = createFallbackMessageList(); // or propagate a clearer error
} else throw e;
} Prevention
- Always use getOrThrow for slots guaranteed by the framework, and plain get() for optional ones.
- Populate all required slots immediately after RunScope creation, before any consumer runs.
- Pass a single RunScope instance through the request; never re-create it mid-request.
When it happens
Trigger: Calling scope.getOrThrow(RunScopeKeys.messageList) (or stored/loopOptions) on a RunScope where that slot was never set — e.g. reading before the scope was populated, or using a scope instance created independently from the one being filled.
Common situations: Custom agent-loop or storage code reading a scope slot before the framework populates it; mixing up two RunScope instances (fresh one vs. the populated one); accidentally clearing/creating the scope mid-request so symbols from another scope are queried.
Related errors
- MastraAuthBetterAuth is not initialized — init() must run fi
- Shared browser not launched. Call createSharedSession() firs
- MastraFactory.finalize() called before prepare()
- GithubReconcileWorker: call init() before start()
- AgentControllerChannels is not bound to an AgentController.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4b2165422aeddd4e.
Report an issue: GitHub.