agalwood/Motrix · error · AppError
TaskCreateTorrentMetaFailed
TaskCreateTorrentMetaFailed
Error message
Failed to persist torrent metadata
What it means
Thrown by create-task-handler.ts:237 when `deps.torrentMetaStore.persist(taskId, torrentBytes)` rejects while saving the `.torrent` sidecar for a BT task created with raw torrent bytes. Without the persisted sidecar the task cannot be re-seeded later, so creation is aborted.
Source
Thrown at src/core/task/create-task-handler.ts:237
const finalPath = path.join(effectiveSaveDir, finalName)
const diskPath = toTempPath(finalPath)
const taskId = newTaskId()
// Anchor "now" early so the hook DTO's requestedAt and the persisted
// task row share a clock — they are written in the same SQLite
// transaction when plugin metadata is staged.
const now = Date.now()
// 2. Persist torrent bytes for the re-seed dance (BT with raw .torrent).
let torrentMetaPath: string | null = null
if (torrentBytes) {
try {
torrentMetaPath = await deps.torrentMetaStore.persist(
taskId,
torrentBytes
)
} catch (cause) {
throw new AppError(
ErrorCode.TaskCreateTorrentMetaFailed,
'Failed to persist torrent metadata',
cause
)
}
}
// 2.5. Pre-create the on-disk slot before handing off to aria2.
// Both task families keep a `.motrix` suffix during download, but
// `diskPath` means different things:
// - BT/Magnet: `diskPath` IS a container directory aria2 populates
// (`dir = diskPath`, `out` dropped). Pre-creating it also
// guarantees `aria2.addTorrent`'s metadata write
// (`<diskPath>/<sha1>.torrent`) succeeds at add time. Without
// this dir, the save fails silently; the resulting task gets a
// data-only `MetadataInfo` and the sqlite3 `task` row is never
// written, so the next pause hits a FOREIGN KEY violation when
// `task_progress` is upserted.View on GitHub (pinned to 1a708ee577)
Solutions
- Verify the metadataDir exists, is writable, and has free space before create-task is invoked.
- Move the metadata store to a stable location that survives reboots.
- Check permissions of the metadataDir for the app's user account.
- Whitelist the metadataDir in antivirus/defender exclusions.
Example fix
// before
try {
torrentMetaPath = await deps.torrentMetaStore.persist(taskId, torrentBytes)
} catch (cause) {
throw new AppError(ErrorCode.TaskCreateTorrentMetaFailed, 'Failed to persist torrent metadata', cause)
}
// after — pre-flight the store and surface the FS reason
await deps.fs.access(deps.torrentMetaStore.dir, deps.fs.constants.W_OK)
.catch(() => { throw new AppError(ErrorCode.TaskCreateTorrentMetaFailed, 'metadataDir not writable') })
torrentMetaPath = await deps.torrentMetaStore.persist(taskId, torrentBytes) Defensive patterns
Strategy: validation
Validate before calling
async function storeWritable(fs, dir) {
try { await fs.access(dir, fs.constants.W_OK); return true } catch { return false }
}
if (!(await storeWritable(deps.fs, deps.torrentMetaStore.dir))) {
// surface 'metadataDir not writable' before create
} Type guard
function isTorrentMetaPersistFailed(e) { return e instanceof AppError && e.code === ErrorCode.TaskCreateTorrentMetaFailed } Try / catch
try {
torrentMetaPath = await deps.torrentMetaStore.persist(taskId, torrentBytes)
} catch (cause) {
throw new AppError(ErrorCode.TaskCreateTorrentMetaFailed, 'Failed to persist torrent metadata', cause)
} Prevention
- Pre-flight that the metadataDir exists and is writable before create.
- Use a stable, non-temp metadataDir that survives reboots.
- Whitelist the metadataDir in antivirus exclusions.
- Monitor free space on the metadataDir volume.
When it happens
Trigger: The metadataDir is on a full or read-only filesystem; permission denied writing the sidecar; the path is invalid (too long, illegal chars); the metadata store volume was unmounted; a transient I/O error mid-write.
Common situations: Default metadataDir points at a temp/external volume that is gone; disk full from large downloads; permissions tightened by an OS update; antivirus blocking writes of `.torrent` files.
Related errors
- MagnetResolveFailed
- TaskCreateDedupExhausted
- TaskFinalizeRenameFailed
- TaskFinalizeMetaMissing
- TaskFinalizeMetaMissing
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/33f006c550cf2792.
Report an issue: GitHub.