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

  1. 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
  2. Raise the file-descriptor limit (ulimit -n 4096 or higher) and reduce concurrentsst dev workers via SST_BUILD_CONCURRENCY
  3. Free leaked fd/pipe resources elsewhere in the process (unstopped workers); ensure worker.Stop() is called
  4. 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

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


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/f8d52ee29c47e052. Report an issue: GitHub.