ppy/osu · error
Can't Read 1
Error message
Can't Read 1
What it means
Thrown while reading the 8-byte little-endian uncompressed-size field of an LZMA replay stream, when ReadByte() returns -1 (EOF) before all 8 bytes are read. The properties header was present but the stream is still truncated within the metadata region. Sibling of the 'input .lzma is too short' check.
Solutions
- Validate data.Length >= 13 before entering readCompressedData so the metadata region is guaranteed present.
- Re-acquire the replay file from its original source and retry the import.
- Wrap the decode in try/catch IOException and skip/quarantine corrupt replays during batch import.
- Audit the replay encoder to ensure it writes the full 13-byte header atomically.
Example fix
// before
int v = replayInStream.ReadByte();
if (v < 0)
throw new IOException("Can't Read 1");
// after (precheck)
if (data.Length < 13)
throw new IOException($"Replay metadata truncated ({data.Length} bytes); need at least 13."); Defensive patterns
Strategy: validation
Validate before calling
if (data == null || data.Length < 13)
throw new IOException($"Replay metadata truncated: {data?.Length ?? 0} bytes."); Try / catch
try { readCompressedData(data, readFunc); }
catch (IOException ex) when (ex.Message.Contains("Read 1")) { /* corrupt replay */ } Prevention
- Check data.Length covers the full 13-byte LZMA header before decoding.
- Reject incomplete replays at the import boundary.
- Audit the replay encoder to write the header atomically.
When it happens
Trigger: The replay byte array contains between 5 and 12 bytes inclusive: enough for the LZMA properties but not enough for the full 8-byte outSize length prefix.
Common situations: Partially-overwritten replay file, a writer bug that wrote the properties header then failed before the length field, or manual slicing of a compressed payload that cut mid-header.
Related errors
- input .lzma is too short
- Bad ticks count read!
- Deserialization of arbitrary type is not supported.
- Legacy replay cannot be converted for the ruleset
- must be false when is specified.
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/17a505a73dd42cef.
Report an issue: GitHub.
Appendix: source
Thrown at osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs:182
return score;
}
private void readCompressedData(byte[] data, Action<StreamReader> readFunc)
{
using (var replayInStream = new MemoryStream(data))
{
byte[] properties = new byte[5];
if (replayInStream.Read(properties, 0, 5) != 5)
throw new IOException("input .lzma is too short");
long outSize = 0;
for (int i = 0; i < 8; i++)
{
int v = replayInStream.ReadByte();
if (v < 0)
throw new IOException("Can't Read 1");
outSize |= (long)(byte)v << (8 * i);
}
long compressedSize = replayInStream.Length - replayInStream.Position;
using (var lzma = LzmaStream.Create(properties, replayInStream, compressedSize, outSize))
using (var reader = new StreamReader(lzma))
readFunc(reader);
}
}
/// <summary>
/// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>.
/// </summary>
/// <param name="score">The score to populate the statistics of.</param>
/// <param name="workingBeatmap">The corresponding <see cref="WorkingBeatmap"/>.</param>
public static void PopulateMaximumStatistics(ScoreInfo score, WorkingBeatmap workingBeatmap)
View on GitHub (pinned to d9c73e12ad)