charmbracelet/crush · error

failed to detach crush server process: %v

Error message

failed to detach crush server process: %v

What it means

Wraps the error from os/exec's Process.Release() after successfully starting the detached server. Release detaches the parent from the child so it won't be reaped; failure usually means the child already exited and was reaped, or the process handle is invalid on this platform.

Source

Thrown at internal/cmd/root.go:899

	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)
	}

	return nil
}

func shouldEnableMetrics(cfg *config.Config) bool {
	if v, _ := strconv.ParseBool(os.Getenv("CRUSH_DISABLE_METRICS")); v {
		return false
	}
	if v, _ := strconv.ParseBool(os.Getenv("DO_NOT_TRACK")); v {
		return false
	}
	if cfg.Options.DisableMetrics {
		return false
	}
	return true
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the server's stderr log file for the real startup failure before Release
  2. Verify server port/config so the child survives long enough to be released
  3. Treat Release failure as non-fatal if the readiness probe confirms the server is healthy
  4. Retry spawnAndWaitReady once, since the failure can be a transient reaping race

Example fix

// before: abort on any Release error
if err := c.Process.Release(); err != nil {
	return fmt.Errorf("failed to detach crush server process: %v", err)
}
// after: log but continue if readiness probe succeeds
if err := c.Process.Release(); err != nil {
	slog.Warn("Failed to detach crush server process", "error", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No practical pre-call validation; verify child health around Release.
ready := waitForServerReady(addr, 5*time.Second)

Try / catch

if err := startDetachedServer(cmd); err != nil {
	if strings.Contains(err.Error(), "detach") && isServerHealthy(addr) {
		slog.Warn("Detach failed but server is healthy; continuing")
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: startDetachedServer calls c.Process.Release() after c.Start(); the child exited immediately after start (crash, port conflict, bad config), or the OS already reaped it, making the handle stale.

Common situations: Server crashes on startup so the process is gone by Release time; sandboxed environments limiting process APIs; race between a supervisor and Release.

Related errors


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