agalwood/Motrix · error · AppError

EngineProcessOwnershipUnverified

EngineProcessOwnershipUnverified

Error message

A verified aria2 process is required for force termination

What it means

Thrown as an AppError (code EngineProcessOwnershipUnverified) by EngineSupervisor.recover when a ForceTerminate recovery action is requested but the supervisor cannot produce a verified expected process descriptor. This fires when expectedProcess() returns null (no binaryPath or no lastStartArgs — meaning start() was never called or recorded no args) OR when request.expectedPid is undefined (the caller didn't specify which PID to terminate). This is a safety guard: force termination requires both a known process fingerprint and an explicit PID.

Source

Thrown at src/core/engine/engine-supervisor.ts:560

    const previousRpcPort = this.settingsManager.getEngine().rpcPort

    if (
      request.action === EngineRecoveryAction.RestoreDefaultPort &&
      previousRpcPort === ENGINE_RPC_PORT
    ) {
      return {
        ok: this.state === EngineState.Ready,
        previousRpcPort,
        rpcPort: previousRpcPort,
        status: this.getStatus(),
      }
    }

    if (request.action === EngineRecoveryAction.ForceTerminate) {
      const expected = this.expectedProcess()
      if (!expected || request.expectedPid === undefined) {
        throw new AppError(
          ErrorCode.EngineProcessOwnershipUnverified,
          'A verified aria2 process is required for force termination'
        )
      }
      await this.processManager.forceTerminateVerified(
        request.expectedPid,
        previousRpcPort,
        expected
      )
    }

    if (request.action === EngineRecoveryAction.SwitchPort) {
      const nextPort = await findAvailablePort(previousRpcPort + 1)
      if (nextPort === null) {
        throw new AppError(
          ErrorCode.EngineStartFailed,
          'No available RPC port was found'
        )

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Ensure start() has been called at least once so expectedProcess() can return a descriptor (binaryPath + lastStartArgs)
  2. Always include expectedPid in the ForceTerminate recovery request — obtain it from the last known engine status (managedPid)
  3. If no process fingerprint exists, use SwitchPort or RestoreDefaultPort recovery instead of ForceTerminate
  4. Check supervisor.getStatus().managedPid before offering the force-terminate option in the UI

Example fix

// before
await supervisor.recover({ action: EngineRecoveryAction.ForceTerminate }) // missing expectedPid
// after
const pid = supervisor.getStatus().managedPid
await supervisor.recover({ action: EngineRecoveryAction.ForceTerminate, expectedPid: pid })
Defensive patterns

Strategy: validation

Validate before calling

function canForceTerminate(supervisor: EngineSupervisor): boolean {
  const status = supervisor.getStatus()
  return status.managedPid !== null
}
// Build the request only if a PID is known:
const pid = supervisor.getStatus().managedPid
if (pid === null) {
  // Use a different recovery action
  await supervisor.recover({ action: EngineRecoveryAction.SwitchPort })
} else {
  await supervisor.recover({ action: EngineRecoveryAction.ForceTerminate, expectedPid: pid })
}

Try / catch

try {
  await supervisor.recover(request)
} catch (e) {
  if (e instanceof AppError && e.code === ErrorCode.EngineProcessOwnershipUnverified) {
    // No verified process — fall back to port switch
    await supervisor.recover({ action: EngineRecoveryAction.SwitchPort })
  } else throw e
}

Prevention

When it happens

Trigger: recover({ action: ForceTerminate, expectedPid }) is called where expectedProcess() is null (this.binaryPath or this.lastStartArgs is empty) or request.expectedPid is not provided.

Common situations: The UI offers a 'force terminate' recovery button before any engine start attempt has recorded process args; the caller omits expectedPid from the recovery request; the supervisor was reset and lost its lastStartArgs; a stale recovery request arrives after a restart cycle cleared the expected process state.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/c0e3248af313b570. Report an issue: GitHub.