sipeed/picoclaw · error

error starting channels: %w

Error message

error starting channels: %w

What it means

One or more channel backends failed to start when ChannelManager.StartAll ran after HTTP listeners were wired. StartAll iterates every enabled channel calling channel.Start(ctx) and aggregates failures as 'channel <name>: <err>', so the wrapped message identifies which channel broke.

Source

Thrown at pkg/gateway/gateway.go:501

	}

	runningServices.authToken = authToken
	runningServices.HealthServer = health.NewServer(listenResult.ProbeHost, cfg.Gateway.Port, authToken)

	var listenAddr string
	if len(listenResult.Listeners) > 0 {
		listenAddr = listenResult.Listeners[0].Addr().String()
	} else {
		listenAddr = net.JoinHostPort(listenResult.ProbeHost, strconv.Itoa(cfg.Gateway.Port))
	}
	runningServices.ChannelManager.SetupHTTPServerListeners(
		listenResult.Listeners,
		listenAddr,
		runningServices.HealthServer,
	)

	if err = runningServices.ChannelManager.StartAll(context.Background()); err != nil {
		return nil, fmt.Errorf("error starting channels: %w", err)
	}

	logChannelVoiceCapabilities(runningServices.ChannelManager, transcriber != nil, ttsAvailable)

	if transcriber != nil {
		// Start Voice Agent Orchestrator after channels are ready.
		vaCtx, vaCancel := context.WithCancel(context.Background())
		runningServices.VoiceAgentCancel = vaCancel
		voiceAgent := asr.NewAgent(msgBus, transcriber)
		voiceAgent.Start(vaCtx)
	}

	healthAddr := net.JoinHostPort(listenResult.ProbeHost, strconv.Itoa(cfg.Gateway.Port))
	fmt.Printf(
		"✓ Health endpoints available at http://%s/health, /ready and /reload (POST)\n",
		healthAddr,
	)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the wrapped per-channel errors in the returned message
  2. Re-validate tokens/credentials for each named channel and refresh them
  3. Check network connectivity/egress rules for the channel APIs
  4. Kill stale gateway processes holding ports, then retry startup
  5. Temporarily set failing channels enabled:false to isolate the rest
Defensive patterns

Strategy: try-catch

Validate before calling

// before StartAll: cheap credential probe per channel where the SDK offers one (e.g. telegram getMe)

Try / catch

if err = cm.StartAll(ctx); err != nil {
    // err aggregates 'channel <name>: <cause>'; parse names to disable-and-retry
    log.Printf("failed channels: %v", err)
}

Prevention

When it happens

Trigger: A channel's Start() failing: invalid Telegram bot token, WhatsApp/Slack webhook unreachable or auth rejected, port already bound by a channel listener; StartAll cancels its dispatch task when no channel starts and returns the joined error, which gateway.go wraps as 'error starting channels'.

Common situations: Expired or rotated API tokens; network egress blocked by firewall/proxy; another instance of the gateway still holding the port; channel API version changes after upgrade.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/f52874beedd14836. Report an issue: GitHub.