henrygd/beszel · warning

chcon failed: %w

Error message

chcon failed: %w

What it means

HandleSELinuxContext sets an SELinux context on the updated binary. When persistent tools (semanage/restorecon) are unavailable, it falls back to running `chcon -t bin_t <path>`; this error wraps a non-zero exit of chcon. The binary has been updated but its SELinux context could not be adjusted, which may prevent it from executing under enforcing SELinux.

Source

Thrown at internal/ghupdate/selinux.go:31

		// SELinux not enabled or getenforce not available
		return nil
	}
	state := strings.TrimSpace(string(out))
	if state == "Disabled" {
		return nil
	}

	ColorPrint(ColorYellow, "SELinux is enabled; applying context…")

	// Try persistent context via semanage+restorecon
	if success := trySemanageRestorecon(path); success {
		return nil
	}

	// Fallback to temporary context via chcon
	if chconPath, err := exec.LookPath("chcon"); err == nil {
		if err := exec.Command(chconPath, "-t", "bin_t", path).Run(); err != nil {
			return fmt.Errorf("chcon failed: %w", err)
		}
		return nil
	}

	return fmt.Errorf("no SELinux tools available (semanage/restorecon or chcon)")
}

// trySemanageRestorecon attempts to set persistent SELinux context using semanage and restorecon.
// Returns true if successful, false otherwise.
func trySemanageRestorecon(path string) bool {
	semanagePath, err := exec.LookPath("semanage")
	if err != nil {
		return false
	}

	restoreconPath, err := exec.LookPath("restorecon")
	if err != nil {
		return false

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Run the update (and context fix) as root, or with CAP_MAC_ADMIN, so chcon can relabel the file.
  2. Verify the target path exists and is a regular file before the context operation.
  3. Install the persistent tooling instead: policycoreutils-python-utils (semanage/restorecon) so a durable rule is used.
  4. If the environment isn't actually SELinux-enforcing, skip the call or set permissive mode (getenforce/setenforce 0) while updating.

Example fix

// before: non-root relabel denied
$ ./myapp update
// chcon failed: exit status 1 (permission denied)

// after: run with sufficient privileges
$ sudo ./myapp update
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat("/sys/fs/selinux"); err != nil {
    return nil // not an SELinux system; skip HandleSELinuxContext
}
if _, err := exec.LookPath("chcon"); err != nil {
    return fmt.Errorf("no SELinux tooling installed")
}
if os.Geteuid() != 0 {
    return fmt.Errorf("relabeling requires root")
}

Type guard

func chconAvailable() bool {
    _, err := exec.LookPath("chcon")
    return err == nil
}

Try / catch

if err := HandleSELinuxContext(binPath); err != nil {
    if strings.Contains(err.Error(), "chcon failed") {
        log.Warn("could not relabel binary; run 'chcon -t bin_t' manually as root", "err", err)
    } else { return err }
}

Prevention

When it happens

Trigger: Calling HandleSELinuxContext on an SELinux-enabled system where semanage/restorecon are absent, chcon exists, but `chcon -t bin_t path` exits non-zero — e.g. permission denied, invalid path, or SELinux policy forbidding the transition.

Common situations: Running as non-root on an SELinux-enforcing host (chcon requires appropriate privileges); the binary path doesn't exist or was moved before this call; policy prevents setting bin_t on that location; minimal container images shipping chcon but no policy support.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/49f3cef2f493da6c. Report an issue: GitHub.