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

  1. Update wsh on both local and remote ends to matching current versions so the stream broker is installed.
  2. Reconnect the wsh client (open a fresh Wave block / re-run preRunSetupRpcClient) and retry.
  3. Fall back to non-streaming read paths (`wsh file read` style commands) if supported by your version.
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/8c06a4b1f6d0a588. Report an issue: GitHub.