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
- Ensure start() has been called at least once so expectedProcess() can return a descriptor (binaryPath + lastStartArgs)
- Always include expectedPid in the ForceTerminate recovery request — obtain it from the last known engine status (managedPid)
- If no process fingerprint exists, use SwitchPort or RestoreDefaultPort recovery instead of ForceTerminate
- 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
- Only offer ForceTerminate in the UI when getStatus().managedPid is non-null
- Always include expectedPid in ForceTerminate recovery requests
- Prefer SwitchPort or RestoreDefaultPort when no verified process fingerprint exists
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
- EngineProcessOwnershipUnverified
- EngineStartFailed
- EngineProcessTerminationFailed
- EngineProtocolError
- EngineStartFailed
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/c0e3248af313b570.
Report an issue: GitHub.