stablyai/orca · error · Error

Benchmark process group anchor changed before signaling

Error message

Benchmark process group anchor changed before signaling

What it means

Thrown inside signalValidatedProcessGroup right after SIGSTOP'ing the anchor (members[0]). The code re-fetches all process identities and looks up the anchor pid; if sameIdentity (pid + pgid + command) no longer matches the pre-stop snapshot, the anchor was replaced in the stop window and signaling the group by -pgid would hit the wrong process. This is a deliberate TOCTOU guard, not a recoverable fault.

Source

Thrown at config/scripts/macos-computer-helper-owner-loss-processes.mjs:283

      operations.signalProcess(groupState.anchorPid, 'SIGCONT')
      groupState.anchorPid = null
    } catch (error) {
      if (error?.code === 'ESRCH') {
        groupState.anchorPid = null
      } else {
        throw new AggregateError([error], 'Benchmark pending anchor recovery failed')
      }
    }
  }
  const anchor = members[0]
  try {
    operations.signalProcess(anchor.pid, 'SIGSTOP')
    groupState.anchorPid = anchor.pid
    const stoppedAnchor = operations
      .processIdentities(true)
      .find((identity) => identity.pid === anchor.pid)
    if (!sameIdentity(stoppedAnchor, anchor)) {
      throw new Error('Benchmark process group anchor changed before signaling')
    }
    operations.signalProcess(-pgid, 'SIGSTOP')
    groupState.stopped = true
    groupState.anchorPid = null
    const stoppedMembers = operations
      .processIdentities(true)
      .filter((identity) => identity.pgid === pgid)
    if (
      stoppedMembers.length === 0 ||
      stoppedMembers.some((identity) => !identity.command.includes(environmentFragment))
    ) {
      throw new Error('Benchmark process group changed before signaling')
    }
    if (signal !== 'SIGSTOP') {
      operations.signalProcess(-pgid, signal)
      if (signal !== 'SIGKILL') {
        operations.signalProcess(-pgid, 'SIGCONT')
      }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Treat as a trial-invalid signal: abort the trial, run compensateStoppedGroup, and re-spawn the helper from scratch
  2. Reduce the window between snapshot and re-check by capturing anchor identity and stopping in the same critical section
  3. Confirm the helper was healthy before signaling (waitForIdentityExit on a no-op signal 0) to avoid stopping an already-dying process
  4. If recurring, raise the helper's SIGCHLD handling so it does not self-terminate on SIGSTOP
Defensive patterns

Strategy: try-catch

Try / catch

try {
  signalValidatedProcessGroup(pgid, frag, sig, state)
} catch (error) {
  if (/anchor changed before signaling/.test(error.message)) {
    respawnHelperAndRetry()
  } else throw error
}

Prevention

When it happens

Trigger: Between operations.signalProcess(anchor.pid, 'SIGSTOP') and the processIdentities(true).find(...) re-check, the anchor exited and the OS recycled its PID for an unrelated process, so the returned identity has a different pgid or command.

Common situations: Long-running benchmark harnesses on systems under heavy process churn, containers where PID recycling is aggressive, or when the anchor helper crashed immediately on SIGSTOP and a sibling process grabbed the PID. Also surfaces if processIdentities is stubbed to return inconsistent data.

Related errors


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