stablyai/orca · error · Error

Owned window-manager processes survived cleanup: ${evidence.

Error message

Owned window-manager processes survived cleanup: ${evidence.windowManagerGroupAfterCleanup.join('; ')}

What it means

Same invariant as the IBus check but for the xfwm4 process group: after the run, stopOwnedProcessGroup(windowManagerProcess.pid) must return an empty list. Survivors mean the window manager (or a compositor child) escaped cleanup and would leak into the next test's X session.

Source

Thrown at config/scripts/run-terminal-ibus-hangul-e2e.mjs:238

      path.join(projectDir, 'test-results', 'terminal-ibus-hangul-native-ibus.log')
    )
    copyFileSync(
      windowManagerLogPath,
      path.join(projectDir, 'test-results', 'terminal-ibus-hangul-native-xfwm4.log')
    )
    writeFileSync(
      path.join(projectDir, 'test-results', 'terminal-ibus-hangul-native-processes.json'),
      `${JSON.stringify(evidence, null, 2)}\n`
    )
  }

  if (evidence.ibusGroupAfterCleanup.length > 0) {
    throw new Error(
      `Owned IBus processes survived cleanup: ${evidence.ibusGroupAfterCleanup.join('; ')}`
    )
  }
  if (evidence.windowManagerGroupAfterCleanup.length > 0) {
    throw new Error(
      `Owned window-manager processes survived cleanup: ${evidence.windowManagerGroupAfterCleanup.join('; ')}`
    )
  }
  return testExitCode
}

async function runOuter() {
  if (process.platform !== 'linux') {
    throw new Error('The native IBus Hangul E2E runner requires Linux/X11')
  }

  const evidenceDir = mkdtempSync(path.join(os.tmpdir(), 'orca-terminal-ime-e2e-'))
  const runtimeDir = path.join(evidenceDir, 'runtime')
  mkdirSync(runtimeDir, { mode: 0o700 })
  mkdirSync(path.join(evidenceDir, 'config'))
  mkdirSync(path.join(evidenceDir, 'cache'))
  console.error(`[terminal-ime] evidence directory: ${evidenceDir}`)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Read the processes.json evidence file for the surviving WM PIDs.
  2. Start xfwm4 with --compositor=off (already set) and confirm no compositor child is spawned.
  3. Run the whole X11 session under xvfb-run inside a PID namespace so the group is reaped on session exit.
  4. Escalate stopOwnedProcessGroup to SIGKILL and re-verify for the WM group specifically.

Example fix

// before
// xfwm4 child compositor survives group kill
// after
// run the harness under a PID namespace
unshare -p --fork --mount-proc pnpm run test:e2e:terminal-ibus-hangul-native
Defensive patterns

Strategy: validation

Validate before calling

const wmSurvivors = await stopOwnedProcessGroup(windowManagerProcess.pid)
if (wmSurvivors.length > 0) {
  console.error('WM survivors:', wmSurvivors)
}

Try / catch

try { /* test body */ }
finally {
  const wmSurvivors = await stopOwnedProcessGroup(windowManagerProcess.pid)
  if (wmSurvivors.length) throw new Error(`Owned window-manager processes survived cleanup: ${wmSurvivors.join('; ')}`)
}

Prevention

When it happens

Trigger: xfwm4 or a compositor/helper it forked survived the group-kill because it was reparented, ignored SIGTERM, or was re-activated by the X server.

Common situations: xfwm4 spawned a compositor process outside its group; the WM ignored the signal under load; the X server restarted the WM via its session manager; cgroup/PID-namespace isolation blocked the kill.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/10a1e7323824fbee. Report an issue: GitHub.