{"record":{"id":"e466b8a21c2589de","repo":"shwenzhang/AndResGuard","slug":"writeentry-new-specnamesid-0-d","errorCode":null,"errorMessage":"writeEntry new specNamesId < 0 %d","messagePattern":"writeEntry new specNamesId < 0 (.+?)","errorType":"exception","errorClass":"brut.androlib.AndrolibException","httpStatus":null,"severity":"error","filePath":"AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/ARSCDecoder.java","lineNumber":669,"sourceCode":"    mPkg.putSpecNamesReplace(mResId, replaceString);\n    // arsc name列混淆成固定名字, 减少string pool大小\n    boolean useFixedName = config.mFixedResName != null && config.mFixedResName.length() > 0;\n    String fixedName = useFixedName ? config.mFixedResName : replaceString;\n    mPkg.putSpecNamesblock(fixedName, replaceString);\n    mType.putSpecResguardName(replaceString);\n  }\n\n  private void writeEntry() throws IOException, AndrolibException {\n    /* size */\n    mOut.writeBytes(mIn, 2);\n    short flags = mIn.readShort();\n    mOut.writeShort(flags);\n    int specNamesId = mIn.readInt();\n    ResPackage pkg = mPkgs[mCurPackageID];\n    if (pkg.isCanResguard()) {\n      specNamesId = mCurSpecNameToPos.get(pkg.getSpecRepplace(mResId));\n      if (specNamesId < 0) {\n        throw new AndrolibException(String.format(\"writeEntry new specNamesId < 0 %d\", specNamesId));\n      }\n    }\n    mOut.writeInt(specNamesId);\n\n    if ((flags & ENTRY_FLAG_COMPLEX) == 0) {\n      writeValue();\n    } else {\n      writeComplexEntry();\n    }\n  }\n\n  /**\n   * @param flags whether read direct\n   */\n  private void readComplexEntry(boolean flags, int specNamesId) throws IOException, AndrolibException {\n    int parent = mIn.readInt();\n    int count = mIn.readInt();\n    for (int i = 0; i < count; i++) {","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/shwenzhang/AndResGuard/blob/e4df245d82f27d9a2d0dd108260a3510cbaba849/AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/ARSCDecoder.java#L651-L687","documentation":"When writing a resource entry back into resources.arsc, AndResGuard looks up the obfuscated spec-name position via pkg.getSpecRepplace(mResId). If the resulting index is negative, the resource ID has no recorded replacement name — the write phase cannot map the entry back to its obfuscated name — so it throws to avoid emitting a corrupt arsc.","triggerScenarios":"writeEntry encounters a resId for which pkg.getSpecRepplace returns null/unknown during the write pass — i.e. an entry present in the arsc that was never assigned an obfuscated name during decode (decode/write desync, or packages mutated between phases).","commonSituations":"Custom code altering ResPackage/spec-name maps between decode and write; partial decode failures swallowed upstream; arsc entries referencing IDs AndResGuard's decode pass skipped; version-mismatched APK processing (decode from one build, write into another).","solutions":["Run decode and write as one uninterrupted pipeline on the same ResPackage[] without external mutation.","Verify all resource entries get replacement names during decode (no earlier AndrolibExceptions swallowed).","Rebuild the APK from sources and re-run AndResGuard on a clean artifact.","Upgrade AndResGuard if the arsc comes from a newer AAPT2 with entry layouts the old decoder mishandles."],"exampleFix":"// before\nResPackage[] pkgs = ARSCDecoder.decode(in, decoder);\npkgs[0].removeSpecNamesReplace(someResId); // custom mutation\nARSCDecoder.write(in, decoder, pkgs); // specNamesId < 0\n// after\nResPackage[] pkgs = ARSCDecoder.decode(in, decoder);\nARSCDecoder.write(in, decoder, pkgs);","handlingStrategy":"validation","validationCode":"for (ResPackage pkg : pkgs) {\n    for (int resId : allEntryResIds) {\n        if (pkg.isCanResguard() && pkg.getSpecRepplace(resId) == null) {\n            throw new IllegalStateException(\"no obfuscated name for resId 0x\" + Integer.toHexString(resId));\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    ARSCDecoder.write(in, decoder, pkgs);\n} catch (AndrolibException e) {\n    if (e.getMessage().contains(\"specNamesId < 0\")) {\n        // decode/write desync; rerun the full decode->write pipeline\n    }\n}","preventionTips":["Run decode and write back-to-back on the same ResPackage[] with no mutation.","Never swallow earlier AndrolibExceptions during decode.","Rebuild from sources when processing fails halfway."],"tags":["arsc","mapping","invariant","apk"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e4df245d82f27d9a2d0dd108260a3510cbaba849","analyzedAt":"2026-09-12T17:49:07.798Z","contentChangedAt":"2026-09-12T17:49:07.798Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}