jesseduffield/lazygit · error
CreateJobObject: %w
Error message
CreateJobObject: %w
What it means
After the pseudoconsole exists, StartPty creates a Job Object (with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE) so closing the job later terminates the whole child process tree — and as a safety net if lazygit itself dies. If CreateJobObject fails, the error is wrapped and the deferred cleanups tear down the pseudoconsole and handles created so far.
Source
Thrown at pkg/commands/oscommands/pty_windows.go:340
_ = windows.CloseHandle(inRead)
_ = windows.CloseHandle(outWrite)
defer func() {
if err != nil {
windows.ClosePseudoConsole(hpc)
if conhost != 0 {
_ = windows.CloseHandle(conhost)
}
}
}()
// The child goes into a job object so that the teardown in Close can
// terminate the whole process tree. KILL_ON_JOB_CLOSE makes the OS do
// that when the last handle to the job is closed, which doubles as a
// safety net: if lazygit exits without running the teardown, the handle
// is closed for it and the tree is reaped.
job, err := windows.CreateJobObject(nil, nil)
if err != nil {
return StartedPty{}, fmt.Errorf("CreateJobObject: %w", err)
}
defer func() {
if err != nil {
// Kills the child on error paths where it was already assigned
// to the job; plain handle cleanup before that.
_ = windows.CloseHandle(job)
}
}()
limits := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{
BasicLimitInformation: windows.JOBOBJECT_BASIC_LIMIT_INFORMATION{
LimitFlags: windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
},
}
if _, err = windows.SetInformationJobObject(
job, windows.JobObjectExtendedLimitInformation,
uintptr(unsafe.Pointer(&limits)), uint32(unsafe.Sizeof(limits)),
); err != nil {
return StartedPty{}, fmt.Errorf("SetInformationJobObject: %w", err)View on GitHub (pinned to c477a2959b)
Solutions
- Run lazygit outside the restrictive host (job-aware CI container, some terminal multiplexers) to confirm the job nesting restriction.
- Free handles/memory and retry if the machine is under resource pressure.
- Report the environment details upstream if plain cmd/PowerShell also fails, since nesting behavior varies by Windows version.
Defensive patterns
Strategy: fallback
Try / catch
sp, err := oscommands.StartPty(cmd, cols, rows)
if err != nil {
if strings.Contains(err.Error(), "CreateJobObject") {
// nested-job restriction (CI/sandbox hosts): run without job-based teardown,
// but then kill the child process group yourself on exit
return startPtyWithoutJob(cmd, cols, rows)
}
return err
} Prevention
- Detect job-nesting-restricted hosts (CI runners, containers) and use a teardown path that kills the process tree directly.
- Don't rely solely on KILL_ON_JOB_CLOSE if you can't guarantee job creation; always pair with explicit cleanup.
- Test PTY spawn in the exact deployment environment, not just a dev desktop.
When it happens
Trigger: windows.CreateJobObject returning an error: the process is already subject to a job that disallows nested job creation, or handle/memory exhaustion at this stage.
Common situations: Running lazygit inside a CI runner, Docker/WSL wrapper, sandbox, or another job-hierarchy that sets JOB_OBJECT_LIMIT_BREAKAWAY_OK off / silent-breakaway-allowed off, blocking new job objects.
Related errors
AI-assisted analysis of jesseduffield/lazygit@c477a2959b (2026-08-15).
Data as JSON: /api/errors/6a0ff16a311bb843.
Report an issue: GitHub.