ppy/osu · error

input .lzma is too short

Error message

input .lzma is too short

What it means

Thrown inside readCompressedData when the LZMA replay payload cannot supply the first 5 bytes (the LZMA properties header). The stream is truncated before the decoder can even begin, so the replay is structurally invalid. This is a hard data-integrity failure, not a decode problem.

Source

Thrown at osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs:174

            if (decodedRank != null)
                score.ScoreInfo.Rank = decodedRank.Value;

            // before returning for database import, we must restore the database-sourced BeatmapInfo.
            // if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
            score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;
            score.ScoreInfo.BeatmapHash = workingBeatmap.BeatmapInfo.Hash;

            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);
            }

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Verify the source .osr file size is non-trivially larger than 5 bytes and re-download/re-extract if it is truncated.
  2. Check the upstream writer/encoder to confirm it flushes the full LZMA blob before closing the stream.
  3. Catch IOException around the decode path and report a 'corrupt replay' user message rather than letting it propagate.
  4. If importing many replays, quarantine files that fail this check instead of aborting the whole import.

Example fix

// before
if (replayInStream.Read(properties, 0, 5) != 5)
    throw new IOException("input .lzma is too short");

// after (caller-side guard)
if (data.Length < 13) // 5 props + 8 size bytes minimum
    throw new IOException($"Replay payload too short ({data.Length} bytes); file is corrupt.");
Defensive patterns

Strategy: validation

Validate before calling

if (data == null || data.Length < 13)
    throw new IOException("Replay payload is truncated; cannot decode.");

Try / catch

try { readCompressedData(data, readFunc); }
catch (IOException) { /* mark replay corrupt, skip import */ }

Prevention

When it happens

Trigger: Replay data array passed to readCompressedData is shorter than 5 bytes, or is empty. Happens with partially downloaded/extracted .osr replay files or a truncated embedded replay stream.

Common situations: Corrupt .osr file download (network cut mid-transfer), replay writer produced a zero-length compressed blob, or the wrong byte slice was handed to the decoder.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/e49425025fc60617. Report an issue: GitHub.