MHSanaei/3x-ui · error

failed to start panel update job: %w

Error message

failed to start panel update job: %w

What it means

Fallback path when systemd-run is unavailable: the updater script is launched as a detached process (setDetachedProcess) with bash -lc. cmd.Start() failing here means the OS could not fork/exec at all — most often resource exhaustion (fork: cannot allocate memory, fork: retry), a full disk affecting temp writes, or bash disappearing between LookPath and Start.

Source

Thrown at internal/web/service/panel/panel.go:290

		} 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)
	if err := cmd.Start(); err != nil {
		_ = os.Remove(scriptPath)
		return 0, fmt.Errorf("failed to start panel update job: %w", err)
	}
	if err := cmd.Process.Release(); err != nil {
		logger.Warning("failed to release panel update process:", err)
	}
	logger.Infof("started panel update job with pid %d", cmd.Process.Pid)
	recordUpdatePID(cmd.Process.Pid)
	launched = true
	return runID, nil
}

// acquireUpdateSlot claims the single in-flight-update slot for runID. It
// refuses while another run is genuinely still in flight, but grants the
// slot immediately once that run's own status file reports a terminal
// result (success or failure) -- a fast failure shouldn't force the next
// attempt to wait out updateStaleAfter for no reason. Past updateStaleAfter
// with no terminal status yet, it grants the slot anyway UNLESS the process
// we recorded (updatePID) is confirmed still alive, so a merely-slow run
// isn't mistaken for a crashed one; past updateHardCeiling it grants the

View on GitHub (pinned to ad32144c42)

Solutions

  1. Free resources: stop xray temporarily or raise the container/service memory & pids limits, then retry the update
  2. Check dmesg/journal for 'fork: cannot allocate memory' or cgroup OOM events
  3. If persistent, run the updater script manually from a root shell

Example fix

# container at limits
docker update --memory 1g --pids-limit 512 <panel-container>
# then retry the web update; or run manually:
bash -lc "$(curl -fsSL <updater-url>)"
Defensive patterns

Strategy: retry

Validate before calling

// precheck spawn capacity
if err := syscall.ForkExec("/bin/true", nil, &syscall.ProcAttr{}); err != nil {
    // system cannot fork right now; free resources before updating
}

Try / catch

_, err := panelService.StartUpdate(false)
if err != nil && strings.Contains(err.Error(), "failed to start panel update job") && strings.Contains(err.Error(), "fork") {
    // resource exhaustion: free memory/pids, then retry once
}

Prevention

When it happens

Trigger: Panel update attempted on a memory-starved VPS (fork fails), or in a container at its pids/memory cgroup limit, so spawning the detached updater fails immediately; scriptPath is cleaned up and the run aborted.

Common situations: Small VPS with heavy xray load hitting cgroup memory limits exactly when updating; containers with a low pids-max; very high process count.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/8881547224015497. Report an issue: GitHub.