valyala/fasthttp · error
prefork: commandproducer must return a started command
Error message
prefork: commandproducer must return a started command
What it means
ErrCommandProducerNotStarted is returned when a CommandProducer returns an *exec.Cmd whose Process is nil, which means cmd.Start() was never called. Prefork expects the producer to hand back an already-started command; merely constructing one with exec.Command is insufficient.
Source
Thrown at prefork/prefork.go:59
// tcpListenerFile is a hook for (*net.TCPListener).File so tests can
// inject failure paths without binding a real socket.
tcpListenerFile = (*net.TCPListener).File
// ErrOverRecovery is returned when child prefork process restarts exceed
// the value of RecoverThreshold.
ErrOverRecovery = errors.New("prefork: exceeding the value of recoverthreshold")
// ErrOnlyReuseportOnWindows is returned when running on Windows without Reuseport.
ErrOnlyReuseportOnWindows = errors.New("prefork: windows only supports reuseport = true")
// ErrCommandProducerNilCmd is returned when a CommandProducer returns
// (nil, nil) instead of a started command.
ErrCommandProducerNilCmd = errors.New("prefork: commandproducer returned nil command")
// ErrCommandProducerNotStarted is returned when a CommandProducer returns
// an *exec.Cmd whose Process is nil (i.e. cmd.Start() was not called).
ErrCommandProducerNotStarted = errors.New("prefork: commandproducer must return a started command")
)
// Logger is used for logging formatted messages. Its method set is intentionally
// identical to fasthttp.Logger so that *fasthttp.Server.Logger can be assigned
// directly.
type Logger interface {
// Printf must have the same semantics as log.Printf.
Printf(format string, args ...any)
}
// Compile-time check that fasthttp.Logger satisfies the local Logger interface;
// keeps the two types in sync if either side ever evolves.
var _ Logger = fasthttp.Logger(nil)
// Prefork implements fasthttp server prefork.
//
// Preforks master process (with all cores) between several child processes
// increases performance significantly, because Go doesn't have to shareView on GitHub (pinned to c96f600972)
Solutions
- Call cmd.Start() inside the CommandProducer before returning it (or return the error from Start()).
- If you cannot start it yourself, use exec.Cmd only via producers that guarantee Start() was invoked.
- Check cmd.Process != nil in tests for your producer.
Example fix
// before
producer := func() (*exec.Cmd, error) {
return exec.Command("app")
}
// after
producer := func() (*exec.Cmd, error) {
cmd := exec.Command("app")
if err := cmd.Start(); err != nil { return nil, err }
return cmd, nil
} Defensive patterns
Strategy: validation
Validate before calling
cmd, err := producer()
if err == nil && (cmd == nil || cmd.Process == nil) {
return errors.New("commandproducer must return a started command")
} Type guard
func isStarted(cmd *exec.Cmd) bool {
return cmd != nil && cmd.Process != nil
} Prevention
- Always call cmd.Start() before returning a Cmd from a producer.
- Assert cmd.Process != nil in producer unit tests.
- Comment your producer contract: "must return a STARTED command".
When it happens
Trigger: A CommandProducer returns `exec.Command("app", args...)` directly without calling `.Start()` on it, then prefork's doCommand validates `cmd.Process == nil` and fails.
Common situations: Implementations that confuse exec.Command (which only builds the Cmd) with exec.Start; refactors that removed the Start() call while keeping the return.
Related errors
- prefork: commandproducer returned nil command
- prefork: exceeding the value of recoverthreshold
- prefork: windows only supports reuseport = true
- prefork: close inherited listener fd: %w
- prefork: resolve %s/%s: %w
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/d571ac7c60e73e67.
Report an issue: GitHub.