subhra74/xdm · error · IOException
Unable to read state:
Error message
Unable to read state:
What it means
DownloadStateIO.LoadSingleSourceHTTPDownloaderState throws IOException("Unable to read state: <id>") when TransactedBinaryDataReader.Read completed but the deserializer (SingleSourceHTTPDownloaderStateFromBytes) produced a null state. This means the <id>.state file in Config.DataDir exists (or a transaction left no usable data) but could not yield a valid SingleSourceHTTPDownloaderState object — typically a corrupt, empty, or format-incompatible state file.
Solutions
- Treat the download as unrecoverable: delete <id>.state from Config.DataDir and start the download again.
- Back up the file first and inspect its size/contents; an empty or tiny file confirms corruption.
- If the file came from another XDM version, restore the state with the matching version or re-create the download.
- Check for leftover transaction artifacts in Config.DataDir and restore the last committed state file if present.
Example fix
// before
var state = DownloadStateIO.LoadSingleSourceHTTPDownloaderState(id); // throws IOException
// after
SingleSourceHTTPDownloaderState state;
try { state = DownloadStateIO.LoadSingleSourceHTTPDownloaderState(id); }
catch (IOException)
{
DownloadStateIO.DeleteState(id); // discard corrupt state
state = null; // fall back to starting a fresh download
} Defensive patterns
Strategy: try-catch
Validate before calling
var path = Path.Combine(Config.DataDir, id + ".state");
if (!File.Exists(path) || new FileInfo(path).Length == 0)
{
// state missing or empty — do not attempt load; start a fresh download
} Type guard
static bool StateFileLooksValid(string dataDir, string id)
{
var p = Path.Combine(dataDir, id + ".state");
try { return File.Exists(p) && new FileInfo(p).Length > 0; }
catch (IOException) { return false; }
} Try / catch
SingleSourceHTTPDownloaderState state;
try { state = DownloadStateIO.LoadSingleSourceHTTPDownloaderState(id); }
catch (IOException ex)
{
Log.Debug(ex, $"corrupt state {id}");
DownloadStateIO.DeleteState(id);
state = null; // fall back to a fresh download
} Prevention
- Shut down the app gracefully so state transactions commit.
- Back up Config.DataDir periodically if download resumability matters.
- Keep the same XDM version for writing and reading state files.
- Exclude Config.DataDir from cloud sync and antivirus to avoid truncation.
When it happens
Trigger: Calling DownloadStateIO.LoadSingleSourceHTTPDownloaderState(id) where the <id>.state file is empty, truncated, corrupted, or written by an incompatible binary format version, so SingleSourceHTTPDownloaderStateFromBytes returns null.
Common situations: App crash/kill mid-write (mitigated by transacted read but not fully); upgrading XDM across a state-format change; manual copying of state files between machines; disk corruption or partial file sync (Dropbox/OneDrive) of the data directory.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13).
Data as JSON: /api/errors/be31478575a3d72a.
Report an issue: GitHub.
Appendix: source
Thrown at app/XDM/XDM.Core/IO/DownloadStateIO.cs:72
#if NET35
ms.CopyTo(stream);
#endif
});
}
}
public static class DownloadStateIO
{
public static SingleSourceHTTPDownloaderState LoadSingleSourceHTTPDownloaderState(string id)
{
SingleSourceHTTPDownloaderState? state = null;
TransactedBinaryDataReader.Read($"{id}.state", Config.DataDir, r =>
{
state = SingleSourceHTTPDownloaderStateFromBytes(r);
});
if (state == null)
{
throw new IOException("Unable to read state: " + id);
}
return state;
}
private static SingleSourceHTTPDownloaderState SingleSourceHTTPDownloaderStateFromBytes(BinaryReader r)
{
var state = new SingleSourceHTTPDownloaderState
{
Id = r.ReadString(),
TempDir = XDM.Messaging.StreamHelper.ReadString(r),
FileSize = r.ReadInt64(),
LastModified = DateTime.FromBinary(r.ReadInt64()),
SpeedLimit = r.ReadInt32(),
Url = new Uri(r.ReadString())
};
if (r.ReadBoolean())
{
XDM.Messaging.StreamHelper.ReadStateHeaders(r, out Dictionary<string, List<string>> headers);
View on GitHub (pinned to 1ca5a25aae)