wavetermdev/waveterm · error
stream broker not available
Error message
stream broker not available
What it means
streamReadFromFile (used by `wsh cat`) relies on RpcClient.StreamBroker to multiplex streaming data. If the broker was never installed on the RPC client, there is no transport for the streamed file data and the call fails immediately with "stream broker not available".
Source
Thrown at cmd/wsh/cmd/wshcmd-file-util.go:96
// Prepare and send chunk
chunk := buf[:n]
appendData := fileData
appendData.Data64 = base64.StdEncoding.EncodeToString(chunk)
err = wshclient.FileAppendCommand(RpcClient, appendData, &wshrpc.RpcOpts{Timeout: int64(fileTimeout)})
if err != nil {
return fmt.Errorf("appending chunk to file: %w", err)
}
}
return nil
}
func streamReadFromFile(ctx context.Context, fileData wshrpc.FileData, writer io.Writer) error {
broker := RpcClient.StreamBroker
if broker == nil {
return fmt.Errorf("stream broker not available")
}
if fileData.Info == nil {
return fmt.Errorf("file info is required")
}
readerRouteId := RpcClientRouteId
if readerRouteId == "" {
return fmt.Errorf("no route id available")
}
conn, err := connparse.ParseURI(fileData.Info.Path)
if err != nil {
return fmt.Errorf("parsing file path: %w", err)
}
writerRouteId := wshutil.MakeConnectionRouteId(conn.Host)
reader, streamMeta := broker.CreateStreamReader(readerRouteId, writerRouteId, 256*1024)
defer reader.Close()
go func() {
<-ctx.Done()
reader.Close()View on GitHub (pinned to a4447c1563)
Solutions
- Update wsh on both local and remote ends to matching current versions so the stream broker is installed.
- Reconnect the wsh client (open a fresh Wave block / re-run preRunSetupRpcClient) and retry.
- Fall back to non-streaming read paths (`wsh file read` style commands) if supported by your version.
- If embedding the RPC client, register a StreamBroker (wshutil) before issuing FileStreamCommand-dependent calls.
Example fix
// before (custom client setup) rpcClient := wshutil.MakeRpcClient(routeId) // no broker // after rpcClient := wshutil.MakeRpcClient(routeId) rpcClient.SetStreamBroker(wshutil.MakeLocalStreamBroker())
Defensive patterns
Strategy: type-guard
Validate before calling
if RpcClient == nil || RpcClient.StreamBroker == nil {
return fmt.Errorf("streaming unsupported by this client; update wsh or use non-streaming read")
} Type guard
func streamCapable(c *wshutil.WshRpc) bool {
return c != nil && c.StreamBroker != nil
} Try / catch
if err := streamReadFromFile(ctx, fileData, writer); err != nil {
if strings.Contains(err.Error(), "stream broker not available") {
// fallback: use FileReadCommand-based read path
}
} Prevention
- Keep wsh versions identical on local and remote ends
- Register a StreamBroker when embedding the wsh RPC client
- Re-establish the RPC client (new Wave block) if broker is missing
- Prefer the non-streaming read API for minimal clients
When it happens
Trigger: Running `wsh cat` (fileCatRun) when RpcClient.StreamBroker is nil — e.g. a wsh client built/connected without stream support, an older server or client version mismatch, or an embedded/test RPC client that skipped broker wiring.
Common situations: Stale or mismatched wsh binary on a remote host predating stream support; custom tooling reusing the wsh RPC client without registering a StreamBroker; regression after partial upgrade of Wave/wsh on one side.
Related errors
- msg.error
- decoding terminal output: %w
- appending chunk to file: %w
- starting remote file stream: %w
- request packets must have resid set
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/8c06a4b1f6d0a588.
Report an issue: GitHub.