agalwood/Motrix · critical · AppError

EngineStartFailed

EngineStartFailed

Error message

Unrecognized aria2 version output from ${binaryPath}

What it means

Thrown as an AppError (code EngineStartFailed) by Aria2ProcessManager.probe when running `aria2c --version` produces output that does not match the regex /aria2 version (\S+)/. The probe runs execForOutput(binaryPath, ['--version']) and passes the stdout to parseVersionOutput, which returns null if the version line is absent. This blocks engine startup because feature detection depends on parsing the version and enabled-features list.

Source

Thrown at src/core/engine/aria2/aria2-process-manager.ts:74

export class Aria2ProcessManager {
  private process: ChildProcess | null = null
  private running = false
  private readonly ownershipFilePath: string | null
  private readonly inspector: Aria2ProcessInspector

  onExit: ((code: number | null, signal: string | null) => void) | null = null
  onError: ((err: Error) => void) | null = null

  constructor(options: Aria2ProcessManagerOptions = {}) {
    this.ownershipFilePath = options.ownershipFilePath ?? null
    this.inspector = options.inspector ?? new Aria2ProcessInspector()
  }

  async probe(binaryPath: string): Promise<EngineFeatureReport> {
    const versionOutput = await this.execForOutput(binaryPath, ['--version'])
    const report = this.parseVersionOutput(versionOutput)
    if (!report) {
      throw new AppError(
        ErrorCode.EngineStartFailed,
        `Unrecognized aria2 version output from ${binaryPath}`
      )
    }
    return report
  }

  private execForOutput(binaryPath: string, args: string[]): Promise<string> {
    return new Promise((resolve, reject) => {
      execFile(binaryPath, args, (err, stdout) => {
        if (err) {
          reject(
            new AppError(
              ErrorCode.EngineStartFailed,
              `Failed to probe aria2 binary at ${binaryPath}: ${err.message}`,
              err
            )
          )

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Run `<binaryPath> --version` manually in a terminal and confirm it prints 'aria2 version X.Y.Z'
  2. Verify the binary is the correct architecture and platform (file <binaryPath>)
  3. Check for missing shared libraries: ldd <binaryPath> (Linux) or otool -L (macOS)
  4. Re-download or reinstall the correct aria2 binary (preferably the Motrix fork)
  5. Ensure binaryPath is an absolute path to the real executable, not a wrapper or alias
Defensive patterns

Strategy: validation

Validate before calling

import { access, constants } from 'fs/promises'
async function verifyAria2Binary(binaryPath: string): Promise<void> {
  await access(binaryPath, constants.X_OK)
  // Optionally pre-check --version output format
}
// Before probe:
await verifyAria2Binary(binaryPath)

Try / catch

try {
  return await processManager.probe(binaryPath)
} catch (e) {
  if (e instanceof AppError && e.code === ErrorCode.EngineStartFailed) {
    // Binary is wrong/corrupt — re-download or re-resolve the path
    await downloadAria2Binary()
    return await processManager.probe(resolvedPath)
  }
  throw e
}

Prevention

When it happens

Trigger: probe(binaryPath) is called; aria2c --version executes but its stdout does not contain the string 'aria2 version <token>' — e.g. the binary prints a help message, an error, a different format, or empty output.

Common situations: binaryPath points to the wrong executable (e.g. a shell script, a different program named aria2c); the aria2 binary is corrupted or for a different platform (e.g. macOS binary on Linux); a very old or heavily patched aria2 fork that changed the --version output format; the binary requires a shared library that is missing and it exits with an error to stderr instead of stdout; PATH resolves to a wrapper script.

Related errors


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