henrygd/beszel · warning

chcon failed

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.

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.

Appendix: 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)