agalwood/Motrix · error · AppError
EngineProtocolError
EngineProtocolError
Error message
Engine returned non-numeric history count: ${result.count} What it means
Thrown as an AppError (code EngineProtocolError) by Aria2Adapter.getHistoryCount when the RPC method getDownloadResultCount returns a result whose count field cannot be parsed into a finite integer via Number.parseInt. This indicates the aria2 engine (or the Motrix fork's sqlite3 persistence layer) returned an unexpected response shape — a protocol violation rather than a user error.
Source
Thrown at src/core/engine/aria2/aria2-adapter.ts:583
return [...active, ...waiting].map((t) => ({
gid: t.gid,
infoHash: t.infoHash || undefined,
}))
}
async listStopped(): Promise<Array<{ gid: string; infoHash?: string }>> {
const stopped = await this.rpc.tellStopped(0, 1000, ['gid', 'infoHash'])
return stopped.map((t) => ({
gid: t.gid,
infoHash: t.infoHash || undefined,
}))
}
async getHistoryCount(filter?: HistoryFilter): Promise<number> {
const result = await this.rpc.getDownloadResultCount(filter)
const n = Number.parseInt(result.count, 10)
if (!Number.isFinite(n)) {
throw new AppError(
ErrorCode.EngineProtocolError,
`Engine returned non-numeric history count: ${result.count}`
)
}
return n
}
async searchHistory(
query: HistorySearchQuery,
offset: number,
num: number
): Promise<DownloadTask[]> {
const rows = await this.rpc.searchDownloadResult(query, offset, num)
return rows.map(translateRawToTask)
}
async exportSession(filePath: string): Promise<void> {
await this.rpc.exportSession(filePath)View on GitHub (pinned to 1a708ee577)
Solutions
- Verify the aria2 binary is the Motrix fork version that supports getDownloadResultCount (check the feature report from probe())
- Restart the aria2 engine to clear any corrupted in-memory state
- Check engine logs for the raw RPC response that produced the non-numeric count
- If using a custom or older aria2 build, fall back to tellStopped length estimation instead of getDownloadResultCount
Defensive patterns
Strategy: try-catch
Try / catch
try {
return await adapter.getHistoryCount(filter)
} catch (e) {
if (e instanceof AppError && e.code === ErrorCode.EngineProtocolError) {
// Engine returned malformed data — restart and retry, or fall back
log.error({ err: e }, 'history count protocol error, returning 0')
return 0
}
throw e
} Prevention
- Ensure the aria2 binary is the Motrix fork that supports getDownloadResultCount (check featureReport from probe())
- Monitor engine RPC responses for unexpected shapes and restart the engine if corruption is detected
- Keep the aria2 fork up to date to avoid sqlite3 persistence protocol mismatches
When it happens
Trigger: this.rpc.getDownloadResultCount(filter) returns an object whose .count is undefined, null, an empty string, or a non-numeric string; Number.parseInt(result.count, 10) produces NaN, which fails Number.isFinite().
Common situations: Aria2 fork version mismatch where getDownloadResultCount is not supported or returns a different shape; a corrupted sqlite3 history database causing the engine to return an error string instead of a count; RPC response deserialization bug; the engine process crashed mid-response and returned a partial JSON.
Related errors
- EngineStartFailed
- EngineProcessOwnershipUnverified
- EngineProcessTerminationFailed
- WebSocket is not connected
- aria2 addTorrent gid must contain exactly 16 hexadecimal cha
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/db6af62a2c94edb1.
Report an issue: GitHub.