Tencent/tinker · error · DexException

Map is unsorted at ${section}

Error message

Map is unsorted at ${section}

What it means

Thrown by TableOfContents.computeSizesFromOffsets when walking sections from the end of the file backwards: a section's offset is greater than the running end boundary (starting from fileSize). This means a section claims to start after a later section ends — i.e. the offset layout is inconsistent with the declared file size.

Source

Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java:251

        Arrays.sort(sections);

        // Skip header section, since its offset must be zero.
        for (int i = 1; i < sections.length; ++i) {
            if (sections[i].off == Section.UNDEF_OFFSET) {
                sections[i].off = sections[i - 1].off;
            }
        }
    }

    public void computeSizesFromOffsets() {
        int end = fileSize;
        for (int i = sections.length - 1; i >= 0; i--) {
            Section section = sections[i];
            if (section.off == Section.UNDEF_OFFSET) {
                continue;
            }
            if (section.off > end) {
                throw new DexException("Map is unsorted at " + section);
            }
            section.byteCount = end - section.off;
            end = section.off;
        }

        dataOff = header.byteCount
                + stringIds.byteCount
                + typeIds.byteCount
                + protoIds.byteCount
                + fieldIds.byteCount
                + methodIds.byteCount
                + classDefs.byteCount;

        dataSize = fileSize - dataOff;
    }

    private Section getSection(short type) {
        for (Section section : sections) {

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Compare the header fileSize field to the actual byte length of the file — a mismatch means truncation; re-fetch or rebuild the dex.
  2. If you author patchers, recompute fileSize, checksum, and signature together after any content change.
  3. Validate the SHA-1 signature field before parsing to catch truncation early with a clearer error.
Defensive patterns

Strategy: validation

Validate before calling

int declaredSize = headerBuf.getInt(32); // fileSize
if (declaredSize != actualFile.length()) throw new IOException("truncated dex: header says " + declaredSize + ", file is " + actualFile.length());

Prevention

When it happens

Trigger: A map/header where a section offset exceeds the actual file size (truncated file, fileSize field wrong, or offsets from a pre-truncation version of the dex).

Common situations: Truncated downloads or partial writes of dex files; patch pipelines that rewrite headers with a stale fileSize; fat binaries sliced incorrectly.

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/a5aad63ba72d4bbf. Report an issue: GitHub.