hashicorp/nomad · error
StreamFramer not running
Error message
StreamFramer not running
What it means
StreamFramer.Send() only works while the framer's goroutine is running; if s.running is false (never started via Run, or stopped via Destroy/Flush), Send returns this sentinel error instead of queuing data. It signals lifecycle misuse of the framer, not an I/O problem.
Source
Thrown at client/lib/streamframer/framer.go:257
// Compute the amount to read from the buffer
size := min(s.data.Len(), s.frameSize)
if size == 0 {
return nil
}
d := s.data.Next(size)
return d
}
// Send creates and sends a StreamFrame based on the passed parameters. An error
// is returned if the run routine hasn't run or encountered an error. Send is
// asynchronous and does not block for the data to be transferred.
func (s *StreamFramer) Send(file, fileEvent string, data []byte, offset int64) error {
s.l.Lock()
defer s.l.Unlock()
// If we are not running, return the error that caused us to not run or
// indicated that it was never started.
if !s.running {
return fmt.Errorf("StreamFramer not running")
}
// Check if not mergeable
if !s.f.IsCleared() && (s.f.File != file || s.f.FileEvent != fileEvent) {
// Flush the old frame
s.send()
}
// Store the new data as the current frame.
if s.f.IsCleared() {
s.f.Offset = offset
s.f.File = file
s.f.FileEvent = fileEvent
}
// Write the data to the buffer
s.data.Write(data)
View on GitHub (pinned to 482b49bf1a)
Solutions
- Start the framer with Run() before issuing any Send() calls
- Check the framer lifecycle: stop producers (streamFile/StreamFixed) before calling Flush()/Destroy()
- Serialize shutdown: close the data source first, wait, then stop the framer
- If a framer was destroyed, create a new StreamFramer for renewed streaming
- Treat this error as a benign signal during shutdown and drop the message
Example fix
// before
framer.Send("file", "tick", data, offset) // after Destroy
// after
if err := framer.Send("file", "tick", data, offset); err != nil {
if strings.Contains(err.Error(), "StreamFramer not running") {
return nil // framer stopped; drop late write
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
func framerReady(s *StreamFramer) bool {
s.l.Lock()
defer s.l.Unlock()
return s.running
} Try / catch
if err := framer.Send(file, event, data, offset); err != nil {
if err.Error() == "StreamFramer not running" {
return nil // expected during shutdown; drop
}
return err
} Prevention
- Always call Run() before Send()
- Stop log producers before Flush()/Destroy()
- Treat this error as benign during task shutdown
- Create a fresh StreamFramer after teardown instead of reusing
When it happens
Trigger: Calling Send() before calling Run(), or after Flush()/Destroy() has stopped the framer; a task's log stream monitor calling Send after the framer was shut down.
Common situations: Race between task shutdown (which stops the framer) and a late log write; forgetting to call Run() before streaming; reusing a StreamFramer after teardown in tests or restarts.
Related errors
- subscription closed
- Unknown log level
- No nomad log file defined
- eventlog.level must be one of INFO, WARN, or ERROR
- failed to generate logging UI
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/3537f25a9c9d3f20.
Report an issue: GitHub.