MHSanaei/3x-ui · error
failed to start panel update job: %w: %s
Error message
failed to start panel update job: %w: %s
What it means
The preferred launch path runs the updater under systemd-run (transient unit). If systemd-run exits non-zero AND its output does not contain the two known 'systemd not available' strings ('System has not been booted with systemd' / 'Failed to connect to bus'), the failure is treated as real: the script file is removed and the wrapped error plus systemd-run's combined output is returned. Known causes: SELinux/AppArmor denial, systemd-run version not supporting the used flags, resource limits on transient units.
Source
Thrown at internal/web/service/panel/panel.go:269
if systemdRun, err := exec.LookPath("systemd-run"); err == nil {
unitName := fmt.Sprintf("x-ui-web-update-%d", time.Now().Unix())
cmd := exec.CommandContext(context.Background(), systemdRun,
"--unit", unitName,
"--setenv", "XUI_MAIN_FOLDER="+mainFolder,
"--setenv", "XUI_SERVICE="+serviceFolder,
"--setenv", "XUI_UPDATE_TAG="+updateTag,
"--setenv", runIDEnv,
"--setenv", statusFileEnv,
bash, "-lc", updateScript,
)
out, err := cmd.CombinedOutput()
if err != nil {
output := strings.TrimSpace(string(out))
if !strings.Contains(output, "System has not been booted with systemd") &&
!strings.Contains(output, "Failed to connect to bus") {
_ = os.Remove(scriptPath)
return 0, fmt.Errorf("failed to start panel update job: %w: %s", err, output)
}
logger.Warning("systemd-run is unavailable, falling back to detached update process:", output)
} else {
logger.Infof("started panel update job via systemd-run unit %s", unitName)
launched = true
return runID, nil
}
}
cmd := exec.CommandContext(context.Background(), bash, "-lc", updateScript)
cmd.Env = append(os.Environ(),
"XUI_MAIN_FOLDER="+mainFolder,
"XUI_SERVICE="+serviceFolder,
"XUI_UPDATE_TAG="+updateTag,
runIDEnv,
statusFileEnv,
)
setDetachedProcess(cmd)View on GitHub (pinned to ad32144c42)
Solutions
- Read the appended output in the error message — it is systemd-run's stderr and names the real cause
- If it is a policy denial, allow transient units for the panel user or adjust SELinux/AppArmor
- As a workaround, run the official update script manually (same script the panel downloads), then restart the panel
Defensive patterns
Strategy: fallback
Validate before calling
if out, err := exec.Command("systemd-run", "--version").CombinedOutput(); err != nil {
// expect the detached-process fallback; if systemd IS present but this fails, investigate policy
} Try / catch
_, err := panelService.StartUpdate(false)
if err != nil && strings.Contains(err.Error(), "failed to start panel update job") {
// parse the appended systemd-run output; if policy denial, fix unit policy or update manually
} Prevention
- Allow transient units for the panel service user on hardened hosts
- Keep a known-good manual update command documented for fallback
When it happens
Trigger: Triggering the update on a host where systemd exists but systemd-run fails for another reason — e.g. 'Failed to start transient service unit: ...' policy denial, or an embedded init with a systemd-run shim that errors oddly.
Common situations: Hardened systems (SELinux enforcing) blocking transient units; old systemd versions (<231) lacking --property/--setenv support variants; OpenRC/Void with a partial systemd compat layer producing unfamiliar errors.
Related errors
- panel web update is supported only on Linux installations
- bash is required to run the panel updater: %w
- failed to start panel update job: %w
- a panel update is already in progress
- download panel updater: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/d01320b7a653d195.
Report an issue: GitHub.