sipeed/picoclaw · error
assign process to job object: %w
Error message
assign process to job object: %w
What it means
Thrown by the Windows isolation backend's post-start hook. After a child process is spawned with a restricted token, the runtime creates a job object (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE), opens the child PID with PROCESS_SET_QUOTA|PROCESS_TERMINATE|PROCESS_QUERY_LIMITED_INFORMATION|SYNCHRONIZE, and calls AssignProcessToJobObject. If that Win32 call fails, isolation setup aborts, the job/process/token handles are closed, and this wrapped error (including the syscall.Errno) is returned.
Source
Thrown at pkg/isolation/platform_windows.go:114
windows.PROCESS_SET_QUOTA|windows.PROCESS_TERMINATE|windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.SYNCHRONIZE,
false,
uint32(cmd.Process.Pid),
)
if err != nil {
_ = windows.CloseHandle(job)
if resources.token != 0 {
_ = resources.token.Close()
}
return fmt.Errorf("open process for job assignment: %w", err)
}
if err = windows.AssignProcessToJobObject(job, proc); err != nil {
_ = windows.CloseHandle(proc)
_ = windows.CloseHandle(job)
if resources.token != 0 {
_ = resources.token.Close()
}
return fmt.Errorf("assign process to job object: %w", err)
}
if resources.token != 0 {
_ = resources.token.Close()
}
resources.job = job
windowsProcessResourcesByPID.Store(cmd.Process.Pid, resources)
go reapWindowsProcessResources(cmd.Process.Pid, proc, job)
return nil
}
func cleanupPendingPlatformResources(cmd *exec.Cmd) {
if cmd == nil {
return
}
resourcesAny, ok := windowsPendingResources.LoadAndDelete(cmd)
if !ok {
returnView on GitHub (pinned to 49183d7e8d)
Solutions
- Inspect the wrapped errno (errors.As to syscall.Errno): ERROR_ACCESS_DENIED (5) points to job/permission confinement, ERROR_NOT_SUPPORTED (50) to nested-job limits on Windows 7
- Verify the child is still alive right after Start (check cmd.ProcessState / wait later); if it exits instantly, fix the command or path being launched
- Run the parent process outside already-restrictive job objects (avoid nesting the runtime inside CI/container jobs), or upgrade the host to Windows 8+ for nested job support
- If confinement is unavoidable, run with isolation disabled on that host (isolation.enabled=false) since the job-object guarantee cannot be established
- Reproduce manually with a minimal Go snippet calling AssignProcessToJobObject to confirm the host policy blocks it
Example fix
# before: launching an instantly-exiting command under isolation
isolation: {enabled: true}
command: ["nonexistent-tool"] # child dies before job assignment
# after: verify the child survives, launch a real command
isolation: {enabled: true}
command: ["C:\\Tools\\tool.exe"] Defensive patterns
Strategy: try-catch
Validate before calling
// before spawning isolated children on windows, detect a confining parent job
var inJob bool
if err := windows.IsProcessInJob(windows.CurrentProcess(), 0, &inJob); err == nil && inJob {
// parent is already job-confined; nested assignment can fail — plan for it or refuse isolation here
log.Warn("parent process is inside a job object; isolation assignment may fail")
} Try / catch
if err := launchIsolated(cmd); err != nil {
if strings.Contains(err.Error(), "assign process to job object") {
var errno syscall.Errno
if errors.As(err, &errno) {
switch errno {
case windows.ERROR_ACCESS_DENIED, windows.ERROR_NOT_SUPPORTED:
// host policy prevents job confinement: kill the unrestricted child
_ = cmd.Process.Kill()
return fmt.Errorf("isolation unavailable on this host (errno %d); refusing to run unconfined", errno)
}
}
}
return err
} Prevention
- Run the parent outside CI/container job sandboxes, or on Windows 8+ where nested jobs are supported
- Only enable isolation for children that outlive the post-start hook — avoid instantly-exiting commands
- Log the unwrapped errno on this path so host-policy denials are diagnosable
When it happens
Trigger: AssignProcessToJobObject failing: (1) the child exited between OpenProcess and assignment (fast-failing command, bad executable path); (2) the child is already in another job that does not allow breakaway/nesting — nested jobs require Windows 8+, so a Windows 7 parent already in a job fails with ERROR_NOT_SUPPORTED / ERROR_ACCESS_DENIED; (3) the parent itself runs inside a restrictive job or sandbox (CI runner, Docker Desktop, EDR) that denies PROCESS_SET_QUOTA-style operations; (4) security software blocking handle operations on the child.
Common situations: Running picoclaw's isolation mode inside CI agents or container sandables that already confine processes to jobs; launching very short-lived children (the process is gone before it can be attached); Windows 7/Server 2008 R2 hosts where a child can belong to only one job; antivirus interference with job assignment.
Related errors
- create low integrity sid: %w
- set token low integrity: %w
- windows isolation does not yet support expose_paths filesyst
- start process hook: %w
- instance root resolved to current directory
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/6ff76a37304dce96.
Report an issue: GitHub.