{"record":{"id":"56a72755935f5071","repo":"mastra-ai/mastra","slug":"channelsessionrejectederror","errorCode":null,"errorMessage":"ChannelSessionRejectedError","messagePattern":"ChannelSessionRejectedError","errorType":"exception","errorClass":"ChannelSessionRejectedError","httpStatus":null,"severity":"error","filePath":"packages/core/src/channels/agent-controller-channels.ts","lineNumber":454,"sourceCode":"    // Bind the mapped thread. Guard is mandatory: `switch` aborts any active\n    // run, so never re-switch when the session is already on this thread.\n    if (session.thread.getId() !== thread.id) {\n      await session.thread.switch({ threadId: thread.id });\n    }\n    await this.runSessionStartHook(session, thread, requestContext);\n    return session;\n  }\n\n  /**\n   * Call the host's resolver and tag anything it throws as a refusal. Covers\n   * synchronous throws too — the hook may return a `Session` directly, so a\n   * plain `.catch()` on the return value would miss them.\n   */\n  private async resolveChannelSession(ctx: ChannelSessionResolveContext): Promise<Session<any>> {\n    try {\n      return await this.resolveSession!(ctx);\n    } catch (cause) {\n      throw new ChannelSessionRejectedError(cause);\n    }\n  }\n\n  /**\n   * Run the configured session-start hook at most once per session. Fires after\n   * the thread binding above, so a hook that persists session settings writes\n   * them to the thread the session actually ends up on.\n   */\n  private async runSessionStartHook(\n    session: Session<any>,\n    thread: Pick<StorageThreadType, 'id' | 'resourceId'>,\n    requestContext?: RequestContext,\n  ): Promise<void> {\n    const onSessionStart = this.onSessionStart;\n    if (!onSessionStart) return;\n    // Memoize before the first await: two messages arriving together on a new\n    // thread both reach this point. The first starts the hook; every later\n    // caller awaits the same run, so no message dispatches before the session","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/channels/agent-controller-channels.ts#L436-L472","documentation":"ChannelSessionRejectedError wraps any failure thrown by the user-configured `resolveSession` hook when AgentControllerChannels tries to establish a channel session. The library re-throws the original cause inside this error so channel code can uniformly detect session resolution failures. It indicates the session factory/hook supplied in AgentControllerConfig rejected (threw or returned a rejected promise).","triggerScenarios":"Calling `session` (or any channel flow that calls resolveChannelSession) when the configured `resolveSession` function in AgentControllerConfig throws — e.g. it fails to look up a thread, hits a storage/backend error, or has a bug.","commonSituations":"Custom resolveSession implementations that query storage that is down or unconfigured; async session factories that reject on network failures; typos in session resolution logic after refactors.","solutions":["Inspect error.cause for the original exception thrown by your resolveSession implementation and fix that root cause first.","Ensure your resolveSession function is async-safe: wrap its internal awaits in try/catch or make sure it cannot throw synchronously.","Verify any storage/Mastra instance your resolveSession depends on is configured and reachable.","Add logging inside your resolveSession to pinpoint which step rejects."],"exampleFix":"// before\nchannels: { resolveSession: async (ctx) => lookupThread(ctx.threadId) } // lookupThread may throw\n// after\nchannels: { resolveSession: async (ctx) => { try { return await lookupThread(ctx.threadId); } catch (e) { logger.error('session resolve failed', e); throw e; } } }","handlingStrategy":"try-catch","validationCode":"if (typeof config.resolveSession !== 'function') throw new Error('resolveSession must be provided');","typeGuard":"function hasCause(e: unknown): e is { cause: unknown } { return typeof e === 'object' && e !== null && 'cause' in e; }","tryCatchPattern":"try { await channelsSession(); } catch (e) { const cause = hasCause(e) ? e.cause : e; logger.error('channel session rejected', cause); }","preventionTips":["Wrap user resolveSession bodies so known failures (storage down, missing thread) are handled explicitly","Test resolveSession against a real storage backend in CI","Log error.cause immediately — the wrapper hides the original stack unless unwrapped"],"tags":["channels","session","wrapped-error"],"backgroundTag":"session-resolution-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}