anomalyco/sst · error
failed to create stdout pipe: %v
Error message
failed to create stdout pipe: %v
What it means
Raised in PythonRuntime.Run (pkg/runtime/python/python.go:202) when cmd.StdoutPipe() on the `uv run lambdaric_python_bridge.py <handler>` worker process fails. StdoutPipe only fails if the exec.Cmd was already started or waited on, or in rare OS pipe-creation failures (fd exhaustion). It is a guard branch that almost never fires in normal use, indicating a runtime misuse or resource exhaustion.
Source
Thrown at pkg/runtime/python/python.go:202
// Add src/ if it exists
srcDir := filepath.Join(projectRoot, "src")
if _, err := os.Stat(srcDir); err == nil {
pythonPaths = append(pythonPaths, srcDir)
}
// Join paths
pythonPath := strings.Join(pythonPaths, string(os.PathListSeparator))
env = append(env, "PYTHONPATH="+pythonPath)
resourceEncPath := filepath.Join(input.Build.Out, "resource.enc")
env = append(env, "SST_KEY_FILE="+resourceEncPath)
}
cmd.Env = env
cmd.Dir = workingDir
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("failed to create stdout pipe: %v", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, fmt.Errorf("failed to create stderr pipe: %v", err)
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start worker process: %v", err)
}
return &worker{
stdout,
stderr,
cmd,
}, nil
}
View on GitHub (pinned to a0bd20f762)
Solutions
- Check the wrapped %v cause: if it mentions 'already started' or 'exec: StdoutPipe after Start', ensure a fresh exec.Cmd is used per Run call
- Raise the file-descriptor limit (ulimit -n 4096 or higher) and reduce concurrentsst dev workers via SST_BUILD_CONCURRENCY
- Free leaked fd/pipe resources elsewhere in the process (unstopped workers); ensure worker.Stop() is called
- Retry the dev command after clearing leaked processes: pkill -f lambdaric_python_bridge
Example fix
// before: reusing a cmd stdout, _ := cmd.StdoutPipe() cmd.Start() stdout2, err := cmd.StdoutPipe() // fails: exec: StdoutPipe after Start // after: build a fresh cmd for each worker cmd := process.CommandContext(ctx, "uv", "run", bridge, handler)
Defensive patterns
Strategy: try-catch
Validate before calling
// before spawning many workers, check fd headroom (Linux/macOS)
n, err := strconv.Atoi(strings.TrimSuffix(shellOut("ulimit", "-n"), "\n"))
if err == nil && n < 1024 { fmt.Println("raise ulimit -n before running sst dev") } Try / catch
w, err := rt.Run(ctx, input)
if err != nil {
if strings.Contains(err.Error(), "failed to create stdout pipe") {
// fd exhaustion or cmd reuse: reduce concurrency / retry with fresh cmd
return retryWithFreshCommand(ctx, input)
}
return err
} Prevention
- Call worker.Stop() for every started worker so pipes/fds are released
- Keep ulimit -n comfortably above the number of concurrent Python functions
- Never reuse an exec.Cmd after Start(); construct a new one per invocation
- Cap concurrency via SST_BUILD_CONCURRENCY on fd-constrained CI runners
When it happens
Trigger: Calling Run twice reusing the same exec.Cmd (pipe already created/started), or the OS refusing to allocate a new pipe because the process is out of file descriptors (ulimit -n too low with many concurrent functions).
Common situations: Dev servers spawning dozens of Python workers in parallel (default build concurrency is 4, but many function workers) hitting ulimit -n; custom forks that re-invoke cmd after Start(); constrained CI containers with very low fd limits.
Related errors
- failed to create stderr pipe: %v
- not found
- expect JSON object open with '{'
- expecting JSON key should be always a string: %T: %v
- JSON value can't be decoded: %T: %v
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/f8d52ee29c47e052.
Report an issue: GitHub.