subhra74/xdm · error · AssembleFailedException

Generic

Generic

Error message

ErrorCode.Generic

What it means

AssembleFailedException(ErrorCode.Generic) is thrown by SingleSourceHTTPDownloader.AssemblePieces when the downloaded file pieces cannot be merged into the final file and no more specific error code applies. In this code path the assembly loop reached a state where the expected piece data was inconsistent (e.g. a piece missing, its size not matching the expected total, or the aggregated bytes not equal to totalSize). The TODO in the source admits the code carries no detail, so 'Generic' means 'piece-set inconsistency during final merge'.

Solutions

  1. Delete the download's part files and restart the download from scratch.
  2. Verify all piece files exist in Config.DataDir and their sizes are non-zero and consistent with the saved state.
  3. Check free disk space and permissions in the target directory, then retry Resume().
  4. If reproducible, capture logs (Log.Debug output) and file a bug; the code explicitly lacks detailed error info (TODO).

Example fix

// before
throw new AssembleFailedException(ErrorCode.Generic);
// after
// Delete parts and re-download when assembly state is inconsistent:
catch (AssembleFailedException)
{
    downloader.DeleteFileParts();
    downloader.StartDownload(); // restart instead of resume
}
Defensive patterns

Strategy: try-catch

Validate before calling

var state = DownloadStateIO.LoadSingleSourceHTTPDownloaderState(id);
var dir = Config.DataDir;
long expected = state.TotalSize;
long actual = state.Pieces.Sum(p => File.Exists(p.Path) ? new FileInfo(p.Path).Length : 0);
bool resumable = expected > 0 && Math.Abs(actual - expected) < 1024 * 1024;
if (!resumable) downloader.DeleteFileParts(); // restart instead of resume

Type guard

static bool HasConsistentPieces(SingleSourceHTTPDownloaderState s) =>
    s != null && s.Pieces != null && s.Pieces.Count > 0 && s.Pieces.All(p => p != null && p.Path != null);

Try / catch

try
{
    downloader.Resume();
}
catch (AssembleFailedException ex) when (ex.ErrorCode == ErrorCode.Generic)
{
    Log.Debug($"piece set inconsistent for {downloader.Id}; restarting");
    downloader.DeleteFileParts();
    downloader.StartDownload();
}

Prevention

When it happens

Trigger: Calling Resume() on a single-source HTTP download whose on-disk part files do not sum to a consistent set: a piece file is missing or empty, piece sizes do not reconcile with totalBytes, or the pieces list state does not match what was written to disk.

Common situations: Resuming a download after a crash or forced kill that left partial/corrupt .part files; moving the download's data directory without all part files; disk cleanup tools deleting part files; mixing state files from different XDM versions.

Related errors


AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13). Data as JSON: /api/errors/8b40d2708b1e61af. Report an issue: GitHub.

Appendix: source

Thrown at app/XDM/XDM.Core/Downloader/Progressive/SingleHttp/SingleSourceHTTPDownloader.cs:443

                                {
                                    throw new AssembleFailedException(
                                        res == MediaProcessingResult.AppNotFound ? ErrorCode.FFmpegNotFound :
                                        ErrorCode.FFmpegError); //TODO: Add more info about error
                                }

                                if (Config.Instance.FetchServerTimeStamp)
                                {
                                    try
                                    {
                                        File.SetLastWriteTime(TargetFile, state.LastModified);
                                    }
                                    catch { }
                                }
                                this.totalSize = totalBytes;
                            }
                            else
                            {
                                throw new AssembleFailedException(ErrorCode.Generic); //TODO: Add more info about error
                            }
                        }
                    }
                    finally
                    {
#if !NET35
                        System.Buffers.ArrayPool<byte>.Shared.Return(buf);
#endif
                    }

                    if (this.cancelFlag.IsCancellationRequested) return;

                    //Console.WriteLine("Total bytes written: {0} total size: {1}", totalBytes, this.totalSize);
                    if (this.totalSize < 1)
                    {
                        this.totalSize = totalBytes;
                    }
                    if (Config.Instance.FetchServerTimeStamp)

View on GitHub (pinned to 1ca5a25aae)