agalwood/Motrix · error · AppError
EngineProcessOwnershipUnverified
EngineProcessOwnershipUnverified
Error message
The process changed or is not verified as Motrix-owned
What it means
Thrown as an AppError (code EngineProcessOwnershipUnverified) by Aria2ProcessManager.forceTerminateVerified when the process currently listening on the given port cannot be verified as safe to terminate. The method inspects the port, then checks three conditions: processInfo exists, its PID matches expectedPid, and processInfo.safeToTerminate is true. If any fails, it refuses to kill — this is a safety guard to prevent terminating an unrelated or external process.
Source
Thrown at src/core/engine/aria2/aria2-process-manager.ts:252
const ownership =
inspected.name === 'unknown'
? EngineProcessOwnership.Unknown
: EngineProcessOwnership.Other
return this.toProcessInfo(inspected, ownership, false)
}
async forceTerminateVerified(
expectedPid: number,
port: number,
expected: ExpectedAria2Process
): Promise<void> {
const processInfo = await this.inspectPort(port, expected)
if (
!processInfo ||
processInfo.pid !== expectedPid ||
!processInfo.safeToTerminate
) {
throw new AppError(
ErrorCode.EngineProcessOwnershipUnverified,
'The process changed or is not verified as Motrix-owned'
)
}
if (
processInfo.ownership === EngineProcessOwnership.CurrentApp &&
this.getPid() === expectedPid
) {
this.kill()
} else {
this.inspector.forceTerminate(expectedPid)
}
const deadline = Date.now() + 5_000
while (this.inspector.isAlive(expectedPid) && Date.now() < deadline) {
await new Promise<void>((resolve) => setTimeout(resolve, 100))
}View on GitHub (pinned to 1a708ee577)
Solutions
- Re-check the current engine status before attempting force termination — the process may have already exited
- Call inspectPort to see what is actually on the port and its ownership classification
- If the process is ExternalAria2 or Other, do not force-kill it — manually stop the external process or switch to a different RPC port instead
- Update expectedPid from the latest engine status before retrying
Defensive patterns
Strategy: try-catch
Validate before calling
async function isSafeToTerminate(processManager: Aria2ProcessManager, port: number, expectedPid: number, expected: ExpectedAria2Process): Promise<boolean> {
const info = await processManager.inspectPort(port, expected)
return info !== null && info.pid === expectedPid && info.safeToTerminate
} Try / catch
try {
await processManager.forceTerminateVerified(expectedPid, port, expected)
} catch (e) {
if (e instanceof AppError && e.code === ErrorCode.EngineProcessOwnershipUnverified) {
// Process changed or isn't ours — use SwitchPort recovery instead
await supervisor.recover({ action: EngineRecoveryAction.SwitchPort })
} else throw e
} Prevention
- Always call inspectPort and verify ownership before attempting force termination
- Use SwitchPort recovery as a fallback when force-terminate is not safe
- Keep expectedPid fresh by reading from the latest engine status
When it happens
Trigger: forceTerminateVerified(expectedPid, port, expected) is called; inspectPort returns null (nothing listening), or the PID on the port differs from expectedPid (process changed/died and something else took the port), or the process is not safeToTerminate (it's an external aria2, unknown process, or other application).
Common situations: The aria2 process already exited naturally and a different process (or nothing) now holds the port; a non-Motrix application is using the port; the expectedPid is stale because the engine restarted with a new PID; ownership record expired or was cleared; an external aria2 instance (not launched by this app) is on the port.
Related errors
- EngineProcessTerminationFailed
- EngineProcessOwnershipUnverified
- EngineProtocolError
- EngineStartFailed
- aria2 addTorrent gid must contain exactly 16 hexadecimal cha
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/03b933e42cbc47ed.
Report an issue: GitHub.