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

  1. Start the framer with Run() before issuing any Send() calls
  2. Check the framer lifecycle: stop producers (streamFile/StreamFixed) before calling Flush()/Destroy()
  3. Serialize shutdown: close the data source first, wait, then stop the framer
  4. If a framer was destroyed, create a new StreamFramer for renewed streaming
  5. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/3537f25a9c9d3f20. Report an issue: GitHub.