charmbracelet/crush · error

failed to get executable path: %v

Error message

failed to get executable path: %v

What it means

startDetachedServer calls os.Executable() to locate the current binary so it can re-exec itself as the detached server process. If the OS cannot resolve the executable path, the error is wrapped as 'failed to get executable path' and server startup aborts.

Source

Thrown at internal/cmd/root.go:858

		if _, err := os.Stat(hostURL.Host); errors.Is(err, fs.ErrNotExist) {
			return nil
		}
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-time.After(100 * time.Millisecond):
		}
	}
	_ = os.Remove(hostURL.Host)
	return nil
}

var safeNameRegexp = regexp.MustCompile(`[^a-zA-Z0-9._-]`)

func startDetachedServer(cmd *cobra.Command, hostURL *url.URL) error {
	exe, err := os.Executable()
	if err != nil {
		return fmt.Errorf("failed to get executable path: %v", err)
	}

	chDir, err := perHostServerDir(hostURL)
	if err != nil {
		return err
	}

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

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Re-run crush from a stable, installed binary (not a deleted or tmp-resident one).
  2. Avoid replacing/renaming the executable while crush is starting; finish upgrades, then restart.
  3. Install the binary in a standard location on a persistent filesystem instead of /tmp or a RAM disk.
Defensive patterns

Strategy: validation

Validate before calling

exe, err := os.Executable()
if err != nil {
	return fmt.Errorf("cannot locate executable: %w", err)
}
if _, err := os.Stat(exe); err != nil {
	return fmt.Errorf("executable missing on disk: %w", err)
}

Prevention

When it happens

Trigger: os.Executable fails with a kernel/OS error: the binary was deleted or replaced while running (Linux returns ENOENT in some delete/rename races), or an exotic exec environment where /proc mappings are unavailable.

Common situations: Upgrading crush (deleting/replacing the binary) while a client is starting a server; running from a tmpfs that was cleaned; executing via wrappers that confuse path resolution; deleted binaries in /tmp.

Related errors


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