{"record":{"id":"ba49221685f4bf57","repo":"mastra-ai/mastra","slug":"no-source-thread-to-clone","errorCode":null,"errorMessage":"No source thread to clone","messagePattern":"No source thread to clone","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agent-controller/session.ts","lineNumber":696,"sourceCode":"        thread: { ...thread, title, updatedAt: new Date() },\n      });\n      this.#owner.emit({ type: 'thread_title_updated', threadId, title });\n    }\n  }\n\n  /** Clone a thread (and its messages), bind the session to the clone, and rebind the stream. */\n  async clone({\n    sourceThreadId,\n    title,\n    resourceId,\n  }: {\n    sourceThreadId?: string;\n    title?: string;\n    resourceId?: string;\n  } = {}): Promise<AgentControllerThread> {\n    const sourceId = sourceThreadId ?? this.#threadId;\n    if (!sourceId) {\n      throw new Error('No source thread to clone');\n    }\n    // Only allow cloning from a source thread this session owns.\n    if (this.#store?.hasStorage()) {\n      await this.#requireOwnedThread({ threadId: sourceId });\n    }\n    return this.#cloneThread({\n      sourceThreadId: sourceId,\n      resourceId: resourceId ?? this.#owner.identity.getResourceId(),\n      title,\n    });\n  }\n\n  async #cloneThread({\n    sourceThreadId,\n    resourceId,\n    title,\n    metadata,\n  }: {","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent-controller/session.ts#L678-L714","documentation":"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.","triggerScenarios":"Calling clone() with no arguments on a session that never bound a thread; calling clone({ sourceThreadId: undefined }) explicitly; calling after unbinding the thread.","commonSituations":"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.","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."],"exampleFix":"// before\nconst t = await session.clone(); // throws when no active thread\n// after\nconst sourceId = session.thread.getId();\nif (!sourceId) throw new Error('Create or select a thread first');\nconst t = await session.clone({ sourceThreadId: sourceId });","handlingStrategy":"type-guard","validationCode":"if (!sourceThreadId && session.thread.getId() === null) throw new Error('Create or select a thread before cloning');","typeGuard":"function canClone(s: { thread: { getId(): string | null } }, sourceThreadId?: string): boolean {\n  return Boolean(sourceThreadId ?? s.thread.getId());\n}","tryCatchPattern":"try {\n  return await session.clone({ sourceThreadId });\n} catch (e) {\n  if (e instanceof Error && e.message === 'No source thread to clone') {\n    return null; // or create a thread first\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["state","lifecycle","threading"],"backgroundTag":"no-active-thread","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}