clash-verge-rev/clash-verge-rev · error · anyhow::Error

failed to configure Job Object for sidecar PID {pid}: {job_e

Error message

failed to configure Job Object for sidecar PID {pid}: {job_error:#}; failed to terminate child: {kill_error:#}

What it means

Windows-only. After spawn succeeds, create_and_assign_sidecar_job(child.pid()) is called to put the sidecar into a Job Object with KILL_ON_JOB_CLOSE so it dies with the app. If Job Object assignment fails, the code attempts to clean up by child.kill(); if that kill ALSO fails, the two errors are combined into this bail and the readiness flow aborts. It is a compound failure: cannot manage the process AND cannot terminate it.

Source

Thrown at src-tauri/src/core/manager/state.rs:157

            crate::core::owner_identity::current_user_pipe_sddl()?,
        );
        let (mut rx, child) = command.spawn().map_err(|error| {
            anyhow::anyhow!(
                "failed to start sidecar core {clash_core:?} with config {} and data directory {}: {error:#}",
                config_file.display(),
                config_dir.display()
            )
        })?;
        #[cfg(target_os = "windows")]
        let job = {
            match create_and_assign_sidecar_job(child.pid()) {
                Ok(job) => job,
                Err(job_error) => {
                    let pid = child.pid();

                    let error = match child.kill() {
                        Ok(()) => job_error,
                        Err(kill_error) => anyhow::anyhow!(
                            "failed to configure Job Object for sidecar PID {pid}: \
                            {job_error:#}; failed to terminate child: {kill_error:#}"
                        ),
                    };

                    logging!(error, Type::Core, "Failed to start sidecar: {error:#}");
                    return Err(error);
                }
            }
        };

        #[cfg(unix)]
        unsafe {
            tauri_plugin_clash_verge_sysinfo::libc::umask(previous_mask)
        };

        let pid = child.pid();
        logging!(trace, Type::Core, "Sidecar started with PID: {}", pid);

View on GitHub (pinned to 5cad0f2799)

Solutions

  1. Read job_error first — most often OpenProcess/AssignProcessToJobObject permission or nesting; run the app outside of job-constrained hosts (e.g. some CI/terminal job wrappers).
  2. Confirm the app (and its service, if elevated) has the necessary process rights to manage the sidecar PID.
  3. If reproducing in CI, disable nested-job restrictions or run the app directly rather than under a job-bearing shell.
  4. Check whether the sidecar crashed instantly — if so, fix the underlying crash and the compound error disappears.
Defensive patterns

Strategy: try-catch

Try / catch

match core_manager.start_core_by_sidecar().await {
    Ok(_) => Ok(()),
    Err(e) if e.to_string().contains("failed to configure Job Object") => {
        // surface the windows job-assignment error; advise running outside job-constrained hosts
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: create_and_assign_sidecar_job returned an error (e.g. OpenProcess/AssignProcessToJobObject failed — permission denied, job nesting limits on older Windows, process already in a conflicting job), and immediately afterward child.kill() also returned an error (process already exited, handle invalid, access denied).

Common situations: Running the app under a parent process that already places children in a Job Object that disallows nested job assignment; antivirus injecting into the child so kill fails; the sidecar exited on its own in the microsecond between assign-attempt and kill so the handle is no longer valid.

Related errors


AI-assisted analysis of clash-verge-rev/clash-verge-rev@5cad0f2799 (2026-08-12). Data as JSON: /api/errors/46915d226f8f9b17. Report an issue: GitHub.