Join our Newsletter — 33% off our NHI Course
Home› FAQ› Cyber Security› What should teams do when an Android app…
Cyber Security

What should teams do when an Android app crashes after enabling R8 or ProGuard?

← Back to all FAQ
By NHI Mgmt Group Editorial Team Updated October 12, 2026 Domain: Cyber Security

Start by tracing the failing class or method back through the retraced stack trace and mapping file, then identify whether reflection or another dynamic lookup depends on names that optimisation changed. Add the smallest keep rule that restores the behaviour, test again, and avoid broad preservation unless the crash proves the scope is still too narrow.

How to localise the crash before changing rules

R8 and ProGuard failures are usually debugged best by treating the obfuscated stack trace as a translation problem first, not a tuning problem. Retracing the crash against the mapping file should tell you which original class, method, or field disappeared from the runtime path, and that narrows the fix to the exact symbol that optimisation changed.

The practical question is whether the app is failing because code was removed, renamed, inlined, or merged in a way the runtime still depends on. That distinction matters because a class that is only referenced through reflection, annotation processing, JNI, serialisation, dependency injection, or dynamically constructed names can look unused to the shrinker even though the app still needs it.

Teams get the fastest signal by reproducing the crash with the same release build settings, then comparing the failing path with a known-good build. If the issue disappears when minification is disabled, that is usually evidence of an over-aggressive rule set, not a product bug in the business logic.

What the keep rule should protect, and what it should not

The best fix is usually a narrow keep rule that preserves only the class, method, or member that runtime lookup requires. Broad preservation can hide the immediate crash, but it also reduces the value of shrinking, keeps dead code alive, and can mask other missing assumptions about how the app discovers or invokes code.

A good rule targets the minimum scope needed to restore behaviour, then gets validated against the full release path. If a reflection call fails only for one package, preserve that package pattern rather than the entire module; if a serializer needs fields but not methods, protect the fields only. The goal is to make the runtime contract explicit, not to exempt the whole feature from optimisation.

Hard-coded secret exposure in mobile apps is a useful reminder that mobile build-time decisions can expose runtime dependencies in surprising ways, especially when code paths or embedded values are shared across SDKs and app variants.

How to verify the fix before shipping again

After adding or adjusting the rule, rerun the exact production build and test the previously failing path under realistic conditions. A passing debug build is not enough, because the crash often appears only after optimisation, resource shrinking, or release-only packaging changes take effect.

Verification should answer two questions: did the retraced symbol now survive the build, and does the original runtime lookup still resolve correctly? If the code path is driven by reflection or generated names, confirm the dependent name strings, annotations, or serialized member names are still available where the app expects them.

It is also worth checking whether the fix introduced collateral retention. When a keep rule is too broad, teams often avoid seeing the next failure until much later because the shrinker can no longer surface dead or inconsistent paths during testing.

Risk and Threat Considerations

Minification crashes are primarily a release integrity and availability risk. The same mechanism that removes dead code can also remove a live dependency if the app relies on dynamic discovery, so a build change can turn into a production outage even when no source code was edited in the affected path.

Failure mechanism: The shrinker cannot always infer reflective, generated, or indirect usage, so it may rename or strip a symbol that the app still resolves at runtime. In mobile apps, that failure mode is common around serializers, dependency injection, JNI bridges, and plugin-style code.

Impact: Users see startup failures, feature-specific crashes, or silent degradation in release builds, and the team may waste time debugging the wrong layer if the mapping file is not used early. Overly broad keep rules can then create a second-order risk by hiding dead code and making future regressions harder to detect.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

OWASP ASVS, CIS Controls v8 and OWASP SAMM set the governance and control requirements practitioners need to meet.

FrameworkControl / ReferenceRelevance
OWASP ASVSV15 — Secure Software DesignMinification crashes often expose unsafe assumptions about reflection and generated code paths.
Recommendation — Review runtime dependencies and preserve only the symbols the app truly needs.
CIS Controls v8CIS-16 — Application Software SecurityRelease-build crashes after R8 or ProGuard are application security defects introduced by build-time transformation.
Recommendation — Validate release builds with minification enabled before shipping changes.
OWASP SAMMBuild — Build SecurityThe issue is rooted in how the build pipeline transforms code and preserves runtime behaviour.
Recommendation — Add release-build checks that catch shrinker-induced regressions early.

Practitioner Guidance

What to prioritise: Treat the first retraced symbol as the most valuable clue, then trace only the dynamic lookup surface that could genuinely depend on it. Start with the smallest rule that restores the failing runtime contract, not with global suppression of shrinking.

What to verify: Confirm the fix in a release-equivalent build, with minification and resource shrinking enabled, and keep the mapping file alongside the failing stack trace for future incidents. If the symbol only exists because of reflection, annotation use, or generated wiring, test that dependency explicitly.

Practitioner takeaway: The right response is usually precision, not permissiveness, preserve only the runtime dependency that optimisation broke, then prove the app still works under the same release conditions that caused the crash.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Reviewed and updated by the NHIMG editorial team on October 12, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org