JuliusBrussee/caveman · error

executable identity unsupported on %s

Error message

executable identity unsupported on %s

What it means

Returned by runstate.processExecutable when it needs to identify the executable behind a PID but the current GOOS is not linux, darwin, or windows. This is a build-target problem: the code was compiled for a platform with no executable-identity strategy (e.g. freebsd, openbsd).

Source

Thrown at proxy/internal/runstate/runstate.go:230

		// Windows validate()'s portBound probe carries the real liveness
		// weight — a dead proxy is not listening.
		return true
	}
	return process.Signal(syscall.Signal(0)) == nil
}

func processExecutable(pid int) (string, error) {
	if runtime.GOOS == "linux" {
		return os.Readlink(filepath.Join("/proc", strconv.Itoa(pid), "exe"))
	}
	if runtime.GOOS == "darwin" {
		out, err := exec.Command("ps", "-o", "comm=", "-p", strconv.Itoa(pid)).Output()
		return strings.TrimSpace(string(out)), err
	}
	if runtime.GOOS == "windows" {
		return processExecutableWindows(pid)
	}
	return "", fmt.Errorf("executable identity unsupported on %s", runtime.GOOS)
}

func portBound(listen string) bool {
	conn, err := net.DialTimeout("tcp", listen, 200*time.Millisecond)
	if err != nil {
		return false
	}
	_ = conn.Close()
	return true
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Build/run on a supported platform: linux, darwin, or windows
  2. If you must run on another unix, port processExecutable for that GOOS (e.g. sysctl KERN_PROC_PATHNAME on the BSDs) and submit it upstream
  3. As an operator fallback, delete the stale run-state JSON under home/run/ so ownership checks skip the unsupported path
  4. Check your build script's GOOS/GOARCH matrix — often the wrong value leaks from a cross-compile variable

Example fix

// before: unsupported platform returns error
return "", fmt.Errorf("executable identity unsupported on %s", runtime.GOOS)

// after (porting example, BSD):
// sysctl kern.proc.pathname.<pid> returns the executable path
mib := []int{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}
// ... sysctl call, return string(path)
Defensive patterns

Strategy: validation

Validate before calling

if runtime.GOOS != "linux" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
    log.Fatal("executable-identity checks unsupported on " + runtime.GOOS + "; use linux/darwin/windows")
}

Type guard

func executableIdentitySupported() bool {
    switch runtime.GOOS {
    case "linux", "darwin", "windows":
        return true
    }
    return false
}

Try / catch

_, err := runstate.New(listen, mode, owner, version)
if err != nil && strings.Contains(err.Error(), "executable identity unsupported") {
    // platform gap: either skip stale-state ownership probing or clear home/run/*.json
    os.RemoveAll(filepath.Join(home, "run"))
}

Prevention

When it happens

Trigger: Compiling the proxy for an unsupported GOOS (GOOS=freebsd go build ...) and then exercising the run-state ownership path that calls processExecutable — typically stale-state detection that wants to know if the recorded PID still belongs to a caveman binary.

Common situations: Cross-compiling to run on a NAS/BSD system; building in a container with an unusual toolchain default; future Go ports (plan9, js/wasm) where the proc APIs do not exist at all.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/14d48794b924899e. Report an issue: GitHub.