Describe the Bug
A code-defined agent configured with channels (per the Channels Quickstart) connects correctly under mastra dev, but silently never connects under mastra start (the built .mastra/output bundle / deployed server). No socket connects, no webhook handler becomes ready, and no error is logged — the server otherwise boots fine and serves /health.
Root cause (traced in @mastra/core@1.41.0):
-
Mastra.addAgent() registers each agent and, for agents with channels, fires the init fire-and-forget with no error handling:
const agentChannelsInstance = mastraAgent.getChannels();
if (agentChannelsInstance) {
// ...getWebhookRoutes()...
void agentChannelsInstance.initialize(this); // no await, no .catch
}
addAgent is invoked from the Mastra constructor (config.agents.forEach(... this.addAgent(...))).
-
AgentChannels.initialize(mastra) (packages/core/src/channels/agent-channels.ts) reads storage as its very first step:
const storage = mastra.getStorage();
const memoryStore = storage ? await storage.getStore("memory") : undefined;
if (!memoryStore) {
throw new Error("Channels require storage to be configured on the Mastra instance. Configure a storage provider like LibSQLStore.");
}
Under the production bundle, mastra.getStorage() is empty at this point (storage isn't wired onto the instance yet when addAgent runs during construction), so it throws — before the Chat SDK instance is created.
-
Because step 1 is void initialize(this) with no .catch, the rejection is swallowed. The server boots normally; the channel is simply dead.
mastra dev wins the timing race (storage is ready when init runs — it logs Using MastraStateAdapter… then Slack socket mode connected); the mastra start bundle loses it and logs neither.
Distinct from #15948 (the 1.29.0 startup crash where channel webhook routes collided with /api prefix validation, since fixed): that was a visible crash from route validation. This is a silent failure from storage init-ordering plus a swallowed void initialize().
Suggested fixes:
- Initialize agent channels after the
Mastra instance has finished wiring storage (or await storage readiness inside the channel-init path) so mastra.getStorage() is populated when AgentChannels.initialize() runs.
- At minimum, stop swallowing the error: wrap the
void agentChannelsInstance.initialize(this) in addAgent with .catch(err => logger.error(...)), mirroring the instance-level #channels init path which already uses try/catch. The silent failure is what makes this so hard to diagnose in production.
Steps To Reproduce
-
Configure a code-defined agent with a Slack channel (socket/gateway mode, the default) plus instance storage — the documented Quickstart:
// agents/support-agent.ts
import { Agent } from '@mastra/core/agent'
import { createSlackAdapter } from '@chat-adapter/slack'
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
model: 'openai/gpt-5.5',
channels: { adapters: { slack: createSlackAdapter() } },
})
// mastra/index.ts
import { Mastra } from '@mastra/core'
import { LibSQLStore } from '@mastra/libsql'
export const mastra = new Mastra({
agents: { supportAgent },
storage: new LibSQLStore({ url: process.env.DATABASE_URL }),
})
-
Run mastra dev → logs Using MastraStateAdapter (subscriptions persist across restarts) then [chat-sdk:slack] Slack socket mode connected. ✅ Works.
-
Run mastra build && mastra start (same env) → server boots and serves /health, but logs none of the channel/chat lines and the Slack socket never connects — and no error is printed. ❌ Broken, silently.
-
Confirm it's getStorage() emptiness (not an uninitialized store): pre-await storage.getStore("memory") before new Mastra(...) returns a ready store, yet the channel still doesn't connect under mastra start.
Link to Minimal Reproducible Example
https://github.com/berrydev-ai/mastra-channels-prod-repro
Expected Behavior
Agent channels should initialize under mastra start (production) exactly as they do under mastra dev — the Slack socket connects (or the webhook handler becomes ready). At minimum, any failure during channel initialization should be surfaced/logged rather than silently swallowed by the un-awaited void initialize().
Environment Information
@mastra/core: 1.41.0
mastra (CLI): 1.12.2
@mastra/libsql: 1.12.1
@chat-adapter/slack: 4.29.0
Runtime: Bun 1.3.14 / Node.js 22
Storage: LibSQL (DATABASE_URL)
Repro command: `mastra build && mastra start` (production) — works under `mastra dev`
Verification
Describe the Bug
A code-defined agent configured with
channels(per the Channels Quickstart) connects correctly undermastra dev, but silently never connects undermastra start(the built.mastra/outputbundle / deployed server). No socket connects, no webhook handler becomes ready, and no error is logged — the server otherwise boots fine and serves/health.Root cause (traced in
@mastra/core@1.41.0):Mastra.addAgent()registers each agent and, for agents with channels, fires the init fire-and-forget with no error handling:addAgentis invoked from theMastraconstructor (config.agents.forEach(... this.addAgent(...))).AgentChannels.initialize(mastra)(packages/core/src/channels/agent-channels.ts) reads storage as its very first step:Under the production bundle,
mastra.getStorage()is empty at this point (storage isn't wired onto the instance yet whenaddAgentruns during construction), so it throws — before the Chat SDK instance is created.Because step 1 is
void initialize(this)with no.catch, the rejection is swallowed. The server boots normally; the channel is simply dead.mastra devwins the timing race (storage is ready when init runs — it logsUsing MastraStateAdapter…thenSlack socket mode connected); themastra startbundle loses it and logs neither.Suggested fixes:
Mastrainstance has finished wiring storage (orawaitstorage readiness inside the channel-init path) somastra.getStorage()is populated whenAgentChannels.initialize()runs.void agentChannelsInstance.initialize(this)inaddAgentwith.catch(err => logger.error(...)), mirroring the instance-level#channelsinit path which already usestry/catch. The silent failure is what makes this so hard to diagnose in production.Steps To Reproduce
Configure a code-defined agent with a Slack channel (socket/gateway mode, the default) plus instance storage — the documented Quickstart:
Run
mastra dev→ logsUsing MastraStateAdapter (subscriptions persist across restarts)then[chat-sdk:slack] Slack socket mode connected. ✅ Works.Run
mastra build && mastra start(same env) → server boots and serves/health, but logs none of the channel/chat lines and the Slack socket never connects — and no error is printed. ❌ Broken, silently.Confirm it's
getStorage()emptiness (not an uninitialized store): pre-await storage.getStore("memory")beforenew Mastra(...)returns a ready store, yet the channel still doesn't connect undermastra start.Link to Minimal Reproducible Example
https://github.com/berrydev-ai/mastra-channels-prod-repro
Expected Behavior
Agent channels should initialize under
mastra start(production) exactly as they do undermastra dev— the Slack socket connects (or the webhook handler becomes ready). At minimum, any failure during channel initialization should be surfaced/logged rather than silently swallowed by the un-awaitedvoid initialize().Environment Information
Verification