In this article

An unreadable Crashlytics stack trace needs symbols that match the exact release and the kind of frame you are decoding. First distinguish Dart obfuscation from Apple native frames or Android native code. A successful app upload does not prove the relevant symbols reached the correct Firebase app.

Firebase's Flutter Crashlytics setup guide, checked October 8, 2026, includes separate symbol instructions for builds using --split-debug-info and optionally --obfuscate. We have not tested your application's crash pipeline.

Identify what is unreadable#

Capture a sanitized sample frame and its release identity. Record the platform, application identifier, marketing version, build number, architecture and build flags. Keep the complete symbol artifacts privately; public examples should not include customer data or internal source paths unnecessarily.

A Dart frame from an obfuscated Flutter build and an unsymbolicated native iOS frame are different diagnostic cases. Do not upload an arbitrary dSYM and assume it explains every unreadable report.

Preserve the matching files at build time#

Store symbols beside the build record as a protected release artifact. Record the source revision, Flutter version, flavor, build flags and artifact checksum. Symbols created by a later rebuild are not reliable substitutes for those generated with the original release.

Use a predictable directory per release instead of repeatedly overwriting one folder. Restrict access and set retention according to your incident-response and privacy requirements.

The evidence chain should read:

text
Crash report release
  -> exact application build
  -> symbol files generated by that build
  -> upload destination
  -> completed upload evidence

A gap in this chain is the next investigation target.

Confirm the destination and upload path#

Firebase's current instructions specify the Firebase Android App ID for Flutter debug-symbol upload, not the Android package name. They also identify the symbol directory as the one passed to --split-debug-info. Apple-platform configuration has its own recommended version requirements and automatic symbol path.

Read the current guidance for your plugin and tool versions before copying an upload command. Check that a staging build did not send its symbols to a production app record, or vice versa. A zero exit code for the wrong destination still leaves the relevant release unreadable.

Inspect upload output for completion or actionable errors without exposing credentials. If CI treats that step as optional, record the failure clearly rather than reporting the entire observability pipeline as successful.

Validate with a controlled test report#

In an authorized non-production environment, use a synthetic exception and harmless metadata. Confirm that the expected report arrives under the intended Firebase app and release, then inspect whether the relevant frame is readable. Follow Firebase's test-exception procedure for the current integration.

Do not deliberately crash a customer session to validate a configuration. Remove or constrain test controls before production distribution.

When symbols were not retained#

Search the original CI artifacts, release storage and build-machine archive. Establish whether an exact match exists before attempting recovery. A rebuild with the same version label can still differ in dependency resolution or toolchain and should not be presented as identical without evidence.

Make symbol retention a release gate for subsequent builds. Our cloud sync versus backup guide explains a related storage principle: having a file somewhere is different from having a verified, recoverable copy of the version you need.