wavetermdev/waveterm · error
no pending stream (call PrepareConnect first)
Error message
no pending stream (call PrepareConnect first)
What it means
StartStream in pkg/jobmanager/jobmanager.go returns this when jm.pendingStreamMeta is nil, meaning the streaming handshake never staged its metadata. The JobManager requires the two-phase flow: PrepareConnect populates pendingStreamMeta, then StartStream consumes it and attaches the stream writer. Calling StartStream out of order leaves nothing to attach, so the library refuses with this sentinel-style message.
Source
Thrown at pkg/jobmanager/jobmanager.go:361
rtnData.HasExited = true
rtnData.ExitCode = exitData.ExitCode
rtnData.ExitSignal = exitData.ExitSignal
rtnData.ExitErr = exitData.ExitErr
}
log.Printf("PrepareConnect: streamid=%s clientSeq=%d serverSeq=%d streamDone=%v streamError=%q hasExited=%v\n", data.StreamMeta.Id, data.Seq, rtnData.Seq, rtnData.StreamDone, rtnData.StreamError, hasExited)
return rtnData, nil
}
func (jm *JobManager) StartStream(msc *MainServerConn) error {
jm.lock.Lock()
defer jm.lock.Unlock()
if jm.Cmd == nil {
return fmt.Errorf("job not started")
}
if jm.pendingStreamMeta == nil {
return fmt.Errorf("no pending stream (call PrepareConnect first)")
}
err := msc.WshRpc.StreamBroker.AttachStreamWriter(jm.pendingStreamMeta, jm.StreamManager)
if err != nil {
return fmt.Errorf("failed to attach stream writer: %w", err)
}
err = jm.StreamManager.SetRwndSize(int(jm.pendingStreamMeta.RWnd))
if err != nil {
return fmt.Errorf("failed to set rwnd size: %w", err)
}
log.Printf("StartStream: streamid=%s rwnd=%d streaming started\n", jm.pendingStreamMeta.Id, jm.pendingStreamMeta.RWnd)
jm.pendingStreamMeta = nil
return nil
}
func MakeJobDomainSocket(clientId string, jobId string) error {View on GitHub (pinned to a4447c1563)
Solutions
- Call jm.PrepareConnect() (and check its error) before jm.StartStream()
- Do not call StartStream twice for the same stream; once it succeeds, pendingStreamMeta is nil and a new PrepareConnect is required
- Add an assertion or log when pendingStreamMeta is nil at StartStream entry to catch ordering bugs early
Example fix
// before
if err := jm.StartStream(); err != nil {
log.Printf("start stream failed: %v", err)
}
// after
if err := jm.PrepareConnect(); err != nil {
log.Printf("prepare connect failed: %v", err)
return err
}
if err := jm.StartStream(); err != nil {
log.Printf("start stream failed: %v", err)
} Defensive patterns
Strategy: validation
Validate before calling
if err := jm.PrepareConnect(); err != nil {
return fmt.Errorf("prepare failed: %w", err)
}
// only now safe to call StartStream Try / catch
if err := jm.StartStream(); err != nil {
if strings.Contains(err.Error(), "no pending stream") {
// ordering bug: re-run PrepareConnect
if perr := jm.PrepareConnect(); perr == nil {
err = jm.StartStream()
}
}
return err
} Prevention
- Always call PrepareConnect immediately before StartStream in a single helper function
- Never reuse a JobManager for a second StartStream without a fresh PrepareConnect
- Guard concurrent StartStream calls with a mutex or once-guard
- Log the two-phase lifecycle so ordering regressions are visible
When it happens
Trigger: Calling jm.StartStream() without a prior successful jm.PrepareConnect() call, or after a previous StartStream already consumed pendingStreamMeta (it is set to nil on success), or after PrepareConnect returned an error and never set the metadata.
Common situations: Wiring the job manager's public methods in the wrong order during setup; retrying StartStream after a successful start; a race where two goroutines both call StartStream and the second finds pendingStreamMeta already cleared; refactoring that dropped the PrepareConnect step.
Related errors
- reading file: %w
- failed to connect client: %w
- failed to set rwnd size: %w
- stream broker not available
- starting remote file stream: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/28127b4f46f9b0cd.
Report an issue: GitHub.