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
- Guard with hasTypeSpec(typeId) before calling getTypeSpec(typeId).
- Verify you are using the correct ResPackage for the resource id: the high byte of the id must equal package.getId().
- When building a table programmatically, always call addTypeSpec(typeId, typeName) before addType/addEntry for that type.
- 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
- Always call hasTypeSpec() before getTypeSpec()
- Match the resource id's package byte to the ResPackage before lookups
- When building tables, addTypeSpec before any addType/addEntry for that typeId
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
- entry spec: pkgId=0x%02x, typeId=0x%02x, entryId=0x%04x
- type: pkgId=0x%02x, typeId=0x%02x, config=%s
- entry: pkgId=0x%02x, typeId=0x%02x, entryId=0x%04x, config=%
- overlayable: pkgId=0x%02x, name=%s
- Repeated alias: pkgId=0x%02x, aliasId=%s
AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14).
Data as JSON: /api/errors/4d5006c3df61568a.
Report an issue: GitHub.