{"record":{"id":"4dbb996800f3fe21","repo":"stablyai/orca","slug":"benchmark-helper-cleanup-failed","errorCode":null,"errorMessage":"Benchmark helper cleanup failed","messagePattern":"Benchmark helper cleanup failed","errorType":"exception","errorClass":"AggregateError","httpStatus":null,"severity":"error","filePath":"config/scripts/macos-computer-helper-owner-loss-processes.mjs","lineNumber":416,"sourceCode":"  recordedCommandFragment,\n  matchingCommandFragments\n) {\n  const errors = []\n  try {\n    killRecordedProcess(recordPath, recordedCommandFragment)\n  } catch (error) {\n    errors.push(error)\n  }\n  try {\n    killProcessMatchingCommand(matchingCommandFragments)\n  } catch (error) {\n    errors.push(error)\n  }\n  if (errors.length === 1) {\n    throw errors[0]\n  }\n  if (errors.length > 1) {\n    throw new AggregateError(errors, 'Benchmark helper cleanup failed')\n  }\n}\n","sourceCodeStart":398,"sourceCodeEnd":419,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/macos-computer-helper-owner-loss-processes.mjs#L398-L419","documentation":"killRecordedAndMatchingProcesses runs two independent cleanup steps — killRecordedProcess (by recorded identity) and killProcessMatchingCommand (by command fragment). Each is wrapped in its own try/catch. If BOTH throw, the errors are merged into an AggregateError so neither cleanup failure is hidden. A single failure rethrows the lone error.","triggerScenarios":"killRecordedProcess(recordPath, recordedCommandFragment) throws AND killProcessMatchingCommand(matchingCommandFragments) throws in the same call.","commonSituations":"Stale record file whose recorded PID was recycled (144/145) while the command-fragment sweep also hits a uid-changed process (143/146); or a benchmark trial where the helper was never spawned, so both paths have nothing valid to kill and the recorded path errors on a malformed record.","solutions":["Inspect AggregateError.errors to see which cleanup path failed and why","Ensure recordPath exists before calling (killRecordedProcess returns false for a missing file, so a missing record should not throw)","Run killProcessMatchingCommand first to clear live helpers, then killRecordedProcess to clear the recorded one, so a stale record does not mask live cleanup","If cleanup is best-effort, wrap the call and log rather than propagate"],"exampleFix":"// before\nkillRecordedAndMatchingProcesses(recordPath, frag, [frag])\n\n// after\ntry {\n  killRecordedAndMatchingProcesses(recordPath, frag, [frag])\n} catch (error) {\n  const causes = error instanceof AggregateError ? error.errors : [error]\n  for (const cause of causes) console.warn('cleanup error:', cause)\n}","handlingStrategy":"try-catch","validationCode":"import { existsSync } from 'node:fs'\nif (!existsSync(recordPath)) {\n  // killRecordedProcess returns false; only sweep by command\n  killProcessMatchingCommand(matchingCommandFragments)\n}","typeGuard":"function isAggregateError(e) {\n  return e instanceof Error && Array.isArray(e.errors)\n}","tryCatchPattern":"try {\n  killRecordedAndMatchingProcesses(recordPath, frag, matchingFrags)\n} catch (error) {\n  const causes = error instanceof AggregateError ? error.errors : [error]\n  for (const c of causes) log.warn('cleanup failed:', c)\n}","preventionTips":["Run killProcessMatchingCommand before killRecordedProcess when the record may be stale","Treat cleanup as best-effort: log and continue rather than fail the whole trial","Confirm recordPath exists before calling to avoid malformed-record errors"],"tags":["cleanup","process-management","aggregate","error-recovery"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}