{"record":{"id":"03b933e42cbc47ed","repo":"agalwood/Motrix","slug":"engineprocessownershipunverified","errorCode":"EngineProcessOwnershipUnverified","errorMessage":"The process changed or is not verified as Motrix-owned","messagePattern":"The process changed or is not verified as Motrix-owned","errorType":"error_code","errorClass":"AppError","httpStatus":null,"severity":"error","filePath":"src/core/engine/aria2/aria2-process-manager.ts","lineNumber":252,"sourceCode":"    const ownership =\n      inspected.name === 'unknown'\n        ? EngineProcessOwnership.Unknown\n        : EngineProcessOwnership.Other\n    return this.toProcessInfo(inspected, ownership, false)\n  }\n\n  async forceTerminateVerified(\n    expectedPid: number,\n    port: number,\n    expected: ExpectedAria2Process\n  ): Promise<void> {\n    const processInfo = await this.inspectPort(port, expected)\n    if (\n      !processInfo ||\n      processInfo.pid !== expectedPid ||\n      !processInfo.safeToTerminate\n    ) {\n      throw new AppError(\n        ErrorCode.EngineProcessOwnershipUnverified,\n        'The process changed or is not verified as Motrix-owned'\n      )\n    }\n\n    if (\n      processInfo.ownership === EngineProcessOwnership.CurrentApp &&\n      this.getPid() === expectedPid\n    ) {\n      this.kill()\n    } else {\n      this.inspector.forceTerminate(expectedPid)\n    }\n\n    const deadline = Date.now() + 5_000\n    while (this.inspector.isAlive(expectedPid) && Date.now() < deadline) {\n      await new Promise<void>((resolve) => setTimeout(resolve, 100))\n    }","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/engine/aria2/aria2-process-manager.ts#L234-L270","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async function isSafeToTerminate(processManager: Aria2ProcessManager, port: number, expectedPid: number, expected: ExpectedAria2Process): Promise<boolean> {\n  const info = await processManager.inspectPort(port, expected)\n  return info !== null && info.pid === expectedPid && info.safeToTerminate\n}","typeGuard":null,"tryCatchPattern":"try {\n  await processManager.forceTerminateVerified(expectedPid, port, expected)\n} catch (e) {\n  if (e instanceof AppError && e.code === ErrorCode.EngineProcessOwnershipUnverified) {\n    // Process changed or isn't ours — use SwitchPort recovery instead\n    await supervisor.recover({ action: EngineRecoveryAction.SwitchPort })\n  } else throw e\n}","preventionTips":["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"],"tags":["aria2","engine","process","ownership","safety","termination"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}