{
  "id": 8374302,
  "title": "Debugging R8 Release-Only Crashes Without Disabling Optimization",
  "url": "https://urgent.news/2026/09/19/debugging-r8-release-only-crashes-without-disabling-optimization",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-19T03:07:27.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/ufebri/debugging-r8-release-only-crashes-without-disabling-optimization-49pd"
  },
  "original_language": "en",
  "account": "A release build of an application may crash only after minification is enabled by R8, a code shrinking tool. Applying a simple fix such as -keep class com.example.** { *; } or disabling R8 entirely may hide the issue, but neither provides insight into the underlying problem. To effectively debug release-only R8 failures, treat them as indirect-reference debugging problems rather than attempts to guess ProGuard rules. The goal is to identify runtime contracts that static analysis cannot see, preserve those contracts, and maintain optimization. Begin by reproducing the failure using the exact release variant that users experience, considering factors like build type, dependency graph, and generated code. Analyze the stack trace provided by R8, which can be preserved in mapping.txt for future reference. Look for runtime mechanisms that expected the missing class, method, field, or other elements to remain discoverable. Common issues include reflection, runtime class loading, JNI, serialization frameworks, and dynamically discovered implementations. Problems often arise when the program encounters code in ways that static analysis cannot fully infer. For example, using Class.forName(className) may introduce runtime dependencies that R8 fails to see. Investigate the rules applied by R8, as the configuration can come from various sources, including the application, Android tooling, and dependencies. Use the -whyareyoukeeping diagnostic rule to understand why specific classes are retained. When writing keep rules, aim for the narrowest scope that expresses the runtime contract, rather than broad rules that keep excessive code. Prefer annotations to make the runtime contract explicit if your code intentionally exposes itself to reflection or discovery. By following these steps, developers can more effectively debug release-only R8 failures and ensure that optimization is applied correctly without disabling it entirely.",
  "summary": "A debug build works. The release build installs. Then one screen crashes only after minification is enabled. The tempting fix is immediate: -keep class com.example.** { *; } Or worse, turn R8 off and ship. Both can make the symptom disappear. Neither tells you what broke. A release-only R8 failure is usually easier to solve when you treat it as an indirect-reference debugging problem , not a…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}