charmbracelet/crush · error

failed to create stdout log file

Error message

failed to create stdout log file: %v

What it means

startDetachedServer redirects the detached server process's stdout to <chDir>/stdout.log by creating that file with os.Create. If creation fails, the error is wrapped as 'failed to create stdout log file' and the spawn is aborted.

Solutions

  1. Check writability of the per-host server directory and fix permissions (chown/chmod) or run as the correct user.
  2. Free disk space / clear quota if the filesystem is full; consider truncating huge old stdout.log files.
  3. Remove any file/directory incorrectly occupying the stdout.log path.
  4. Point the cache directory at a writable location via the appropriate env (XDG_CACHE_HOME).
Defensive patterns

Strategy: validation

Validate before calling

logPath := filepath.Join(chDir, "stdout.log")
if info, err := os.Lstat(logPath); err == nil && info.IsDir() {
	return fmt.Errorf("%s is a directory; remove it before starting", logPath)
}
if err := checkDirWritable(chDir); err != nil {
	return fmt.Errorf("server dir not writable: %w", err)
}

Prevention

When it happens

Trigger: os.Create(stdoutPath) fails: the per-host dir is unwritable, the disk is full, a directory named stdout.log exists, or security software blocks file creation in the cache dir.

Common situations: Read-only cache filesystem in containers; disk quota exceeded from oversized existing stdout.log files; permission drift after running as another user; logs dir managed/mounted specially.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/dc5c715b7fa64db2. Report an issue: GitHub.

Appendix: source

Thrown at internal/cmd/root.go:882

	}

	cmdArgs := []string{"server"}
	if clientHost != server.DefaultHost() {
		cmdArgs = append(cmdArgs, "--host", clientHost)
	}

	// Use context.Background() so the parent's context cancellation does not
	// kill the spawned server. detachProcess (Setsid on !windows,
	// DETACHED_PROCESS on windows) is what truly detaches the child from
	// this process's lifetime.
	c := exec.CommandContext(context.Background(), exe, cmdArgs...)
	stdoutPath := filepath.Join(chDir, "stdout.log")
	stderrPath := filepath.Join(chDir, "stderr.log")
	detachProcess(c)

	stdout, err := os.Create(stdoutPath)
	if err != nil {
		return fmt.Errorf("failed to create stdout log file: %v", err)
	}
	defer stdout.Close()
	c.Stdout = stdout

	stderr, err := os.Create(stderrPath)
	if err != nil {
		return fmt.Errorf("failed to create stderr log file: %v", err)
	}
	defer stderr.Close()
	c.Stderr = stderr

	if err := c.Start(); err != nil {
		return fmt.Errorf("failed to start crush server: %v", err)
	}

	if err := c.Process.Release(); err != nil {
		return fmt.Errorf("failed to detach crush server process: %v", err)
	}

View on GitHub (pinned to 7944b8e522)