shwenzhang/AndResGuard · error

the old mapping file packagename is malformed, it should be…

Error message

the old mapping file packagename is malformed, it should be like com.tencent.mm.R.attr.test, yours %s

What it means

While parsing the old proguard mapping.txt in keep-mapping mode, each 'from -> to' line without a '/' is treated as a resource-id mapping whose 'from' name must contain the marker ".R." (e.g. com.tencent.mm.R.attr.test). If nameBefore lacks ".R.", the parser cannot extract the package name and throws this IOException. It indicates the mapping file is not the expected proguard resource mapping format.

Solutions

  1. Use the mapping.txt actually produced alongside the previous obfuscated build (one that contains res name entries like com.pkg.R.drawable.name), not a classes-only mapping
  2. Verify each mapping line's left side contains .R. for resource entries, or a '/' for file entries; fix or remove malformed lines
  3. If R8 output format is incompatible, regenerate the mapping with proguard or with the AndResGuard version matching your build chain

Example fix

// before (mapping.txt entry)
com.pkg.SomeClass -> com.pkg.a:
// after (mapping.txt entry)
com.pkg.R.drawable.icon -> com.pkg.a.a
Defensive patterns

Strategy: validation

Validate before calling

java.io.BufferedReader r = new java.io.BufferedReader(new java.io.FileReader(mappingFile));
String line;
while ((line = r.readLine()) != null) {
  java.util.Matcher m = java.util.regex.Pattern.compile("\\s+(.*)->(.*)").matcher(line);
  if (m.find() && !m.group(1).contains("/") && !m.group(1).contains(".R.")) {
    throw new IllegalStateException("mapping line lacks .R. marker: " + line);
  }
}
r.close();

Try / catch

try {
  new Configuration(configFile, ...);
} catch (IOException e) {
  if (e.getMessage().contains("packagename is malformed")) {
    // replace the old mapping.txt with one from a matching obfuscated build
  }
  throw e;
}

Prevention

When it happens

Trigger: A line in the old mapping.txt whose left-hand side (nameBefore) matches the MAP_PATTERN (\s+(.*)->(.*)) but contains neither a '/' (file mapping) nor a ".R." segment (resource mapping) — e.g. class-name-only entries or a mapping.txt from a proguard configuration that does not emit resource names in the expected form.

Common situations: Feeding AndResGuard a plain code mapping.txt (classes only) instead of one containing resource mappings; mapping produced by R8 with different formatting than proguard; editing mapping.txt by hand and corrupting resource entries.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12). Data as JSON: /api/errors/7167ed6f4719ddf3. Report an issue: GitHub.

Appendix: source

Thrown at AndResGuard-core/src/main/java/com/tencent/mm/resourceproguard/Configuration.java:491

      while (line != null) {
        if (line.length() > 0) {
          Matcher mat = MAP_PATTERN.matcher(line);

          if (mat.find()) {
            String nameAfter = mat.group(2);
            String nameBefore = mat.group(1);
            nameAfter = nameAfter.trim();
            nameBefore = nameBefore.trim();

            //如果有这个的话,那就是mOldFileMapping
            if (line.contains("/")) {
              mOldFileMapping.put(nameBefore, nameAfter);
            } else {
              //这里是resid的mapping
              int packagePos = nameBefore.indexOf(".R.");
              if (packagePos == -1) {
                throw new IOException(String.format("the old mapping file packagename is malformed, "
                                                    + "it should be like com.tencent.mm.R.attr.test, yours %s\n",
                    nameBefore
                ));
              }
              String packageName = nameBefore.substring(0, packagePos);
              int nextDot = nameBefore.indexOf(".", packagePos + 3);
              String typeName = nameBefore.substring(packagePos + 3, nextDot);

              String beforename = nameBefore.substring(nextDot + 1);
              String aftername = nameAfter.substring(nameAfter.indexOf(".", packagePos + 3) + 1);

              HashMap<String, HashMap<String, String>> typeMap;

              if (mOldResMapping.containsKey(packageName)) {
                typeMap = mOldResMapping.get(packageName);
              } else {
                typeMap = new HashMap<>();
              }

View on GitHub (pinned to e4df245d82)