iBotPeaches/Apktool · error · AndrolibException

Missing value string pool.

Error message

Missing value string pool.

What it means

When a resource value has type TYPE_STRING, BinaryResourceParser resolves its data field as an index into the table's global value string pool. If no RES_TABLE_VALUE_POOL / string pool of type values was parsed before the entries, that lookup is impossible and this error is thrown.

Source

Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/BinaryResourceParser.java:685

        int type = mIn.readUnsignedByte();
        int data = mIn.readInt();

        return parseItem(typeName, inBag, type, data);
    }

    private ResValue parseItem(String typeName, boolean inBag, int type, int data) throws AndrolibException {
        // ID resource values are either encoded as a boolean (false) or a resource reference.
        // A boolean (false) is no longer allowed in XML, replace with a placeholder value.
        // A resource reference is handled normally, unless it's @null.
        if (typeName.equals("id") && (data == 0 || (type != ResValue.TYPE_REFERENCE
                && type != ResValue.TYPE_DYNAMIC_REFERENCE))) {
            return ResCustom.ID;
        }

        // Special handling for strings and file references.
        if (type == ResValue.TYPE_STRING) {
            if (mValueStringPool == null) {
                throw new AndrolibException("Missing value string pool.");
            }

            CharSequence strValue = mValueStringPool.getText(data);

            // If a string is not allowed here, assume it's a file reference.
            // ResFileDecoder will replace it if it's an invalid file reference.
            if (strValue instanceof String && strValue.length() > 0 && !inBag && !typeName.equals("string")) {
                return new ResFileReference((String) strValue);
            }

            return new ResString(strValue);
        }

        return ResItem.parse(mPackage, type, data);
    }

    private void parseLibrary(ResChunkPullParser parser) throws IOException {
        // ResTable_lib_header

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Verify the table header's string pool chunk exists and precedes package data (hex-dump around offset 0x0C).
  2. Decode an unobfuscated build of the same app.
  3. If producing arsc programmatically, always emit the global value string pool even when it looks empty.
  4. Report the sample upstream — apktool sometimes adds tolerances for known packer quirks.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    parser.parse(in);
} catch (AndrolibException e) {
    if ("Missing value string pool.".equals(e.getMessage())) {
        // table-level value string pool stripped but still referenced
    }
}

Prevention

When it happens

Trigger: An arsc whose package entries reference string values while the table-level value string pool chunk is missing or was skipped — typically a stripped/obfuscated pool or a chunk-order violation at table scope (not package scope).

Common situations: Packers that remove 'unused' string pools while leaving references to them; resource optimizers with bugs that drop the value pool when it still has live references; malformed fuzzing corpora.

Related errors


AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14). Data as JSON: /api/errors/e148b650edaf2922. Report an issue: GitHub.