{"record":{"id":"3537f25a9c9d3f20","repo":"hashicorp/nomad","slug":"streamframer-not-running","errorCode":null,"errorMessage":"StreamFramer not running","messagePattern":"StreamFramer not running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/lib/streamframer/framer.go","lineNumber":257,"sourceCode":"\t// Compute the amount to read from the buffer\n\tsize := min(s.data.Len(), s.frameSize)\n\tif size == 0 {\n\t\treturn nil\n\t}\n\td := s.data.Next(size)\n\treturn d\n}\n\n// Send creates and sends a StreamFrame based on the passed parameters. An error\n// is returned if the run routine hasn't run or encountered an error. Send is\n// asynchronous and does not block for the data to be transferred.\nfunc (s *StreamFramer) Send(file, fileEvent string, data []byte, offset int64) error {\n\ts.l.Lock()\n\tdefer s.l.Unlock()\n\t// If we are not running, return the error that caused us to not run or\n\t// indicated that it was never started.\n\tif !s.running {\n\t\treturn fmt.Errorf(\"StreamFramer not running\")\n\t}\n\n\t// Check if not mergeable\n\tif !s.f.IsCleared() && (s.f.File != file || s.f.FileEvent != fileEvent) {\n\t\t// Flush the old frame\n\t\ts.send()\n\t}\n\n\t// Store the new data as the current frame.\n\tif s.f.IsCleared() {\n\t\ts.f.Offset = offset\n\t\ts.f.File = file\n\t\ts.f.FileEvent = fileEvent\n\t}\n\n\t// Write the data to the buffer\n\ts.data.Write(data)\n","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/lib/streamframer/framer.go#L239-L275","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nframer.Send(\"file\", \"tick\", data, offset) // after Destroy\n// after\nif err := framer.Send(\"file\", \"tick\", data, offset); err != nil {\n    if strings.Contains(err.Error(), \"StreamFramer not running\") {\n        return nil // framer stopped; drop late write\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"func framerReady(s *StreamFramer) bool {\n    s.l.Lock()\n    defer s.l.Unlock()\n    return s.running\n}","typeGuard":null,"tryCatchPattern":"if err := framer.Send(file, event, data, offset); err != nil {\n    if err.Error() == \"StreamFramer not running\" {\n        return nil // expected during shutdown; drop\n    }\n    return err\n}","preventionTips":["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"],"tags":["streaming","lifecycle","logging","goroutines"],"backgroundTag":"resource-not-running","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}