mastra-ai/mastra · error
No source thread to clone
Error message
No source thread to clone
What it means
clone() copies a source thread; the source defaults to the session's currently bound thread. When no explicit sourceThreadId is given and the session has no active thread (#threadId is null), there is nothing to copy and the library throws this fail-fast error.
Source
Thrown at packages/core/src/agent-controller/session.ts:696
thread: { ...thread, title, updatedAt: new Date() },
});
this.#owner.emit({ type: 'thread_title_updated', threadId, title });
}
}
/** Clone a thread (and its messages), bind the session to the clone, and rebind the stream. */
async clone({
sourceThreadId,
title,
resourceId,
}: {
sourceThreadId?: string;
title?: string;
resourceId?: string;
} = {}): Promise<AgentControllerThread> {
const sourceId = sourceThreadId ?? this.#threadId;
if (!sourceId) {
throw new Error('No source thread to clone');
}
// Only allow cloning from a source thread this session owns.
if (this.#store?.hasStorage()) {
await this.#requireOwnedThread({ threadId: sourceId });
}
return this.#cloneThread({
sourceThreadId: sourceId,
resourceId: resourceId ?? this.#owner.identity.getResourceId(),
title,
});
}
async #cloneThread({
sourceThreadId,
resourceId,
title,
metadata,
}: {View on GitHub (pinned to 75dd419e61)
Solutions
- Bind or create a thread first so the session has a current thread, then call clone().
- Pass an explicit sourceThreadId to clone({ sourceThreadId }).
- Guard the UI action: disable clone until the session reports it has an active thread.
Example fix
// before
const t = await session.clone(); // throws when no active thread
// after
const sourceId = session.thread.getId();
if (!sourceId) throw new Error('Create or select a thread first');
const t = await session.clone({ sourceThreadId: sourceId }); Defensive patterns
Strategy: type-guard
Validate before calling
if (!sourceThreadId && session.thread.getId() === null) throw new Error('Create or select a thread before cloning'); Type guard
function canClone(s: { thread: { getId(): string | null } }, sourceThreadId?: string): boolean {
return Boolean(sourceThreadId ?? s.thread.getId());
} Try / catch
try {
return await session.clone({ sourceThreadId });
} catch (e) {
if (e instanceof Error && e.message === 'No source thread to clone') {
return null; // or create a thread first
}
throw e;
} Prevention
- Disable clone controls until a thread is active
- Pass explicit sourceThreadId instead of relying on the default
- Re-check thread binding after any unbind operation
- Initialize a thread at session start when cloning is expected
When it happens
Trigger: Calling clone() with no arguments on a session that never bound a thread; calling clone({ sourceThreadId: undefined }) explicitly; calling after unbinding the thread.
Common situations: Forking 'the current conversation' before any conversation exists; wiring a clone button active on a fresh session; a flow that cleared the thread id earlier.
Related errors
- No active thread on this session
- Thread not found: ${threadId}
- Mode not found: ${this.#id}
- Cannot start a destroyed sandbox
- Step not prepared yet — call prepare() first
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ba49221685f4bf57.
Report an issue: GitHub.