iBotPeaches/Apktool · error · UndefinedResObjectException

type spec: pkgId=0x%02x, typeId=0x%02x

Error message

type spec: pkgId=0x%02x, typeId=0x%02x

What it means

UndefinedResObjectException thrown by ResPackage.getTypeSpec(typeId) when no ResTypeSpec exists for the given type id in this package. Type specs are created from RES_TABLE_TYPE_SPEC chunks in resources.arsc; the error means a resource reference resolves to a typeId that was never declared for the package — a mismatch between the resource table metadata and the code/data using it.

Source

Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/table/ResPackage.java:82

        return mGroup.getId();
    }

    public String getName() {
        return mGroup.getName();
    }

    public int getIndex() {
        return mIndex;
    }

    public boolean hasTypeSpec(int typeId) {
        return mTypeSpecs.containsKey(typeId);
    }

    public ResTypeSpec getTypeSpec(int typeId) throws UndefinedResObjectException {
        ResTypeSpec typeSpec = mTypeSpecs.get(typeId);
        if (typeSpec == null) {
            throw new UndefinedResObjectException(
                String.format("type spec: pkgId=0x%02x, typeId=0x%02x", getId(), typeId));
        }
        return typeSpec;
    }

    public ResTypeSpec addTypeSpec(int typeId, String typeName) throws AndrolibException {
        ResTypeSpec typeSpec = mTypeSpecs.get(typeId);
        if (typeSpec != null) {
            throw new AndrolibException(
                String.format("Repeated type spec: pkgId=0x%02x, typeId=0x%02x, typeName=%s",
                    getId(), typeId, typeName));
        }

        typeSpec = new ResTypeSpec(this, typeId, typeName);
        mTypeSpecs.put(typeId, typeSpec);
        return typeSpec;
    }

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Guard with hasTypeSpec(typeId) before calling getTypeSpec(typeId).
  2. Verify you are using the correct ResPackage for the resource id: the high byte of the id must equal package.getId().
  3. When building a table programmatically, always call addTypeSpec(typeId, typeName) before addType/addEntry for that type.
  4. For split/bundle APKs, decode the base APK together with its splits so all type specs are loaded.

Example fix

// before
ResTypeSpec spec = pkg.getTypeSpec(typeId); // throws if absent

// after
if (!pkg.hasTypeSpec(typeId)) {
    throw new IllegalArgumentException("type 0x" + Integer.toHexString(typeId) + " not in package 0x" + Integer.toHexString(pkg.getId()));
}
ResTypeSpec spec = pkg.getTypeSpec(typeId);
Defensive patterns

Strategy: type-guard

Validate before calling

int pkgId = (resId >>> 24) & 0xff;
if (pkgId != resPackage.getId()) {
    throw new IllegalArgumentException("resource id belongs to package 0x" + Integer.toHexString(pkgId));
}

Type guard

boolean hasTypeSpec(ResPackage pkg, int typeId) {
    return pkg.hasTypeSpec(typeId);
}

Try / catch

try {
    ResTypeSpec spec = pkg.getTypeSpec(typeId);
} catch (UndefinedResObjectException ex) {
    // type never declared for this package; skip resource
}

Prevention

When it happens

Trigger: Calling getTypeSpec with a typeId from a resource id whose package id does not match this ResPackage; obfuscated arsc with stripped type spec chunks; referencing a type that only exists in a split APK's resources.arsc; calling addEntry (which internally calls getTypeSpec) for a type never added via addTypeSpec.

Common situations: Decoding app bundles where types are spread across splits; aggressively obfuscated APKs (resource name/ID remapping tools); programmatic resource-table construction that forgets addTypeSpec before adding entries; cross-package lookups that forget to select the right package.

Related errors


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