{"record":{"id":"f52874beedd14836","repo":"sipeed/picoclaw","slug":"error-starting-channels-w","errorCode":null,"errorMessage":"error starting channels: %w","messagePattern":"error starting channels: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gateway/gateway.go","lineNumber":501,"sourceCode":"\t}\n\n\trunningServices.authToken = authToken\n\trunningServices.HealthServer = health.NewServer(listenResult.ProbeHost, cfg.Gateway.Port, authToken)\n\n\tvar listenAddr string\n\tif len(listenResult.Listeners) > 0 {\n\t\tlistenAddr = listenResult.Listeners[0].Addr().String()\n\t} else {\n\t\tlistenAddr = net.JoinHostPort(listenResult.ProbeHost, strconv.Itoa(cfg.Gateway.Port))\n\t}\n\trunningServices.ChannelManager.SetupHTTPServerListeners(\n\t\tlistenResult.Listeners,\n\t\tlistenAddr,\n\t\trunningServices.HealthServer,\n\t)\n\n\tif err = runningServices.ChannelManager.StartAll(context.Background()); err != nil {\n\t\treturn nil, fmt.Errorf(\"error starting channels: %w\", err)\n\t}\n\n\tlogChannelVoiceCapabilities(runningServices.ChannelManager, transcriber != nil, ttsAvailable)\n\n\tif transcriber != nil {\n\t\t// Start Voice Agent Orchestrator after channels are ready.\n\t\tvaCtx, vaCancel := context.WithCancel(context.Background())\n\t\trunningServices.VoiceAgentCancel = vaCancel\n\t\tvoiceAgent := asr.NewAgent(msgBus, transcriber)\n\t\tvoiceAgent.Start(vaCtx)\n\t}\n\n\thealthAddr := net.JoinHostPort(listenResult.ProbeHost, strconv.Itoa(cfg.Gateway.Port))\n\tfmt.Printf(\n\t\t\"✓ Health endpoints available at http://%s/health, /ready and /reload (POST)\\n\",\n\t\thealthAddr,\n\t)\n","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/gateway/gateway.go#L483-L519","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","solutions":["Read the wrapped per-channel errors in the returned message","Re-validate tokens/credentials for each named channel and refresh them","Check network connectivity/egress rules for the channel APIs","Kill stale gateway processes holding ports, then retry startup","Temporarily set failing channels enabled:false to isolate the rest"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before StartAll: cheap credential probe per channel where the SDK offers one (e.g. telegram getMe)","typeGuard":null,"tryCatchPattern":"if err = cm.StartAll(ctx); err != nil {\n    // err aggregates 'channel <name>: <cause>'; parse names to disable-and-retry\n    log.Printf(\"failed channels: %v\", err)\n}","preventionTips":["Validate channel tokens before restart (provider API probes)","Monitor port availability for listener channels","Disable broken channels instead of failing the whole boot"],"tags":["gateway","channels","network","startup","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}