subhra74/xdm · error · IOException
Unable to read state:
Error message
Unable to read state:
What it means
DownloadStateStore.LoadSingleSourceHTTPDownloaderState throws IOException("Unable to read state: <id>") when the transacted read of <id>.state leaves the state variable null after SingleSourceHTTPDownloaderStateFromBytes runs. This is the DownloadStateStore twin of the DownloadStateIO loader: it enforces that a stored state file for a single-source HTTP download either loads completely or throws.
Solutions
- Delete the offending <id>.state from Config.DataDir and restart the download.
- Restore the state file from backup, matching the XDM version that wrote it.
- Check for orphaned transaction temp files next to the state file and clean/restore as appropriate.
- If recurring, verify disk health and free space on the volume holding Config.DataDir.
Example fix
// before
var state = DownloadStateStore.LoadSingleSourceHTTPDownloaderState(id); // throws
// after
SingleSourceHTTPDownloaderState state;
try { state = DownloadStateStore.LoadSingleSourceHTTPDownloaderState(id); }
catch (IOException) { DownloadStateStore.DeleteState(id); state = null; /* start fresh */ } 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)
{
// start a fresh download instead of calling Load
} 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 = DownloadStateStore.LoadSingleSourceHTTPDownloaderState(id); }
catch (IOException)
{
DownloadStateStore.DeleteState(id);
state = null; // restart download
} Prevention
- Commit state writes gracefully — avoid abrupt terminations.
- Keep read and write versions of the state format in sync.
- Backup the state directory before version upgrades.
- Check for leftover transaction files and clean them after crashes.
When it happens
Trigger: Calling DownloadStateStore.LoadSingleSourceHTTPDownloaderState(id) with a corrupt, empty, truncated, or format-incompatible <id>.state file in Config.DataDir, causing the byte-level deserializer to return null.
Common situations: Crash or forced termination between state-write and commit; XDM upgrade changing the state binary layout; disk corruption; users manually restoring/pasting state files from other installs.
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/3c2531e645dcad6a.
Report an issue: GitHub.
Appendix: source
Thrown at app/XDM/XDM.Core/IO/DownloadStateStore.cs:72
#if NET35
ms.CopyTo(stream);
#endif
});
}
}
public static class DownloadStateStore
{
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)