iBotPeaches/Apktool · error · UndefinedResObjectException

type: pkgId=0x%02x, typeId=0x%02x, config=%s

Error message

type: pkgId=0x%02x, typeId=0x%02x, config=%s

What it means

UndefinedResObjectException thrown by ResPackage.getType(typeId, config) when no ResType exists for the (typeId, config) pair. ResType objects represent a type in one specific configuration (e.g. drawable for en-us); the error means that type/config combination was never created, most commonly because the type has no entry under the requested (often default) configuration.

Source

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

    public boolean hasType(int typeId) {
        return hasType(typeId, ResConfig.DEFAULT);
    }

    public boolean hasType(int typeId, ResConfig config) {
        Pair<Integer, ResConfig> typeKey = Pair.of(typeId, config);
        return mTypes.containsKey(typeKey);
    }

    public ResType getType(int typeId) throws UndefinedResObjectException {
        return getType(typeId, ResConfig.DEFAULT);
    }

    public ResType getType(int typeId, ResConfig config) throws UndefinedResObjectException {
        Pair<Integer, ResConfig> typeKey = Pair.of(typeId, config);
        ResType type = mTypes.get(typeKey);
        if (type == null) {
            throw new UndefinedResObjectException(
                String.format("type: pkgId=0x%02x, typeId=0x%02x, config=%s", getId(), typeId, config));
        }
        return type;
    }

    public ResType addType(int typeId) throws UndefinedResObjectException {
        return addType(typeId, ResConfig.DEFAULT);
    }

    public ResType addType(int typeId, ResConfig config) throws UndefinedResObjectException {
        Pair<Integer, ResConfig> typeKey = Pair.of(typeId, config);
        ResType type = mTypes.get(typeKey);
        if (type != null) {
            // We can safely skip adding existing types.
            return type;
        }

        ResTypeSpec typeSpec = getTypeSpec(typeId);

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Use hasType(typeId, config) before getType(typeId, config).
  2. If you need any config, iterate the available configs for the type instead of assuming ResConfig.DEFAULT exists.
  3. When constructing tables, ensure addType(typeId, config) happens before any get for that pair.

Example fix

// before
ResType type = pkg.getType(typeId); // implies ResConfig.DEFAULT

// after
ResConfig config = pkg.hasType(typeId, ResConfig.DEFAULT) ? ResConfig.DEFAULT : firstAvailableConfig(pkg, typeId);
ResType type = pkg.getType(typeId, config);
Defensive patterns

Strategy: type-guard

Validate before calling

ResConfig config = pkg.hasType(typeId, ResConfig.DEFAULT)
    ? ResConfig.DEFAULT
    : pickExistingConfig(pkg, typeId);

Type guard

boolean hasTypeForConfig(ResPackage pkg, int typeId, ResConfig config) {
    return pkg.hasType(typeId, config);
}

Try / catch

try {
    ResType type = pkg.getType(typeId, config);
} catch (UndefinedResObjectException ex) {
    // no values for this type under requested config; try other configs or skip
}

Prevention

When it happens

Trigger: Calling getType(typeId) which defaults to ResConfig.DEFAULT when the type only has non-default configs; looking up a config that exists for another type but not this one; programmatic construction calling get before addType.

Common situations: Resource tables where a string/drawable exists only for specific locales or densities; code assuming every type has a default-config entry; handling localized apps and app bundles with per-density splits.

Related errors


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