Flutter 'Signed in Debug Mode' Google Play Upload Error: The 5-Step Fix (2026)

By · Published 2026-11-10 · Last verified 2026-11-10

Why does Google Play say my Flutter app bundle was signed in debug mode?

Because a new Flutter project's release build is signed with the debug key until you change it. The generated android/app/build.gradle.kts sets the release build type to signingConfigs.getByName("debug"), with a code comment saying so, and Google Play rejects the upload with "You uploaded an APK or Android App Bundle that was signed in debug mode. You need to sign your APK or Android App Bundle in release mode." The fix is five steps: create an upload keystore, reference it in key.properties, load it in Gradle, point the release build at it, then clean and rebuild. Checked against the Flutter and Android documentation on 2026-11-10.

GSPTeck is giosaia's indie studio that builds and ships Flutter and Firebase apps on Google Play, and this is the first upload error most new Flutter developers hit.

Grid of the 5-step Flutter fix for the signed in debug mode error: create an upload keystore, add android/key.properties, load it in build.gradle.kts, point release at the release config, clean and rebuild, then verify fingerprints
The 5-step debug-mode fix.

What does the Flutter template do by default?

Flutter's template signs release builds with the debug keystore so that flutter run --release works before you have a key. The Flutter Android release guide shows the generated block with the comment "Signing with the debug keys for now", and tells you to replace it with a release signing config.

The Android app signing documentation explains why the store refuses it: the debug certificate is created by the build tools and is "insecure by design", so most app stores, including Google Play, don't accept apps signed with it. Android Studio stores that key in $HOME/.android/debug.keystore.

The 5-step debug-mode fix

Follow these steps in order; most failed fixes skip step 5 or have a wrong path in step 2.

  1. Create an upload keystore. On macOS or Linux, Flutter's guide gives: keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -storetype JKS -keysize 2048 -validity 10000 -alias upload. If keytool isn't on your path, flutter doctor -v prints the Java binary location next to it.
  2. Create android/key.properties. Four lines: storePassword, keyPassword, keyAlias=upload and storeFile with the full path to the .jks file. On Windows, write the path with double backslashes.
  3. Load the file in Gradle. At the top of android/app/build.gradle.kts, import java.util.Properties and java.io.FileInputStream, create keystoreProperties and load rootProject.file("key.properties") if it exists.
  4. Point the release build at it. Inside android, add signingConfigs { create("release") { ... } } reading keyAlias, keyPassword, storeFile and storePassword, and in buildTypes change the release line to signingConfig = signingConfigs.getByName("release").
  5. Clean and rebuild. Run flutter clean, then flutter build appbundle. The Flutter guide notes you might need flutter clean after changing the Gradle file so cached builds don't affect signing.
Two columns contrasting the Flutter template's release build signed with the debug config with a release signing config that reads android/key.properties
Template default versus the fixed release config.

Prefer a dialog to a command line? The Android signing documentation also describes creating the upload key in Android Studio: Build, Generate Signed Bundle/APK, choose Android App Bundle, then Create new under the key store path. Use that only to make the .jks file; still wire it into Gradle with steps 2 to 4, or every flutter build appbundle from the terminal goes back to the debug key.

Older projects use the Groovy file android/app/build.gradle instead; the same five steps apply, with signingConfig signingConfigs.release in the release block. The finished bundle is written to build/app/outputs/bundle/release/.

How do you check which key signed the bundle before uploading?

Print the bundle's certificate and compare its SHA-256 fingerprint with your upload key's; if they match, Play will accept the signature. Two keytool commands do it.

CheckCommandWhat you want to see
Your upload keykeytool -list -v -keystore ~/upload-keystore.jks -alias uploadThe SHA-256 fingerprint of your key
The built bundlekeytool -printcert -jarfile build/app/outputs/bundle/release/<bundle>.aabThe same SHA-256 and the owner name you typed
Gradle's view./gradlew signingReport in the android folderThe release variant pointing at your .jks, not debug.keystore

The keytool reference documents -printcert -jarfile for reading the certificate of a signed file. If the fingerprints differ, the release block is still using debug, or key.properties wasn't found.

Why does the error come back after the fix?

Usually because Gradle never loaded key.properties, or because an old build was uploaded. The template only loads the file if it exists, so a wrong location silently leaves the signing values empty.

Four steps to check the signing key before upload: keytool -list -v on the upload key, keytool -printcert on the bundle, Gradle signingReport, and matching SHA-256
Checking the key before you upload.

Upload key or app signing key: which one is this?

The key you just made is the upload key. Flutter's guide explains that Android uses two keys: you sign the .aab with an upload key, and with Play App Signing, Google signs the APKs users download with the app signing key. Losing the upload key is recoverable through a reset; our guide to resetting a lost Flutter upload key covers it.

Back up the .jks file and its passwords. Android's documentation recommends a validity of 25 years or more for app signing keys, and says Google Play requires the signing key's validity to end after 22 October 2033; the 10,000-day validity in Flutter's command clears that.

What usually goes wrong next?

Once signing works, the next two upload errors are a reused version code and a Google sign-in failure on the Play build. Version code already used explains the pubspec version number, and Google Sign-In failing on the Play release explains why the app signing key's SHA-1 must be registered in Firebase. Our Flutter Firebase release checklist lists every check before each release.

See the apps GSPTeck ships with this setup on the GSPTeck homepage.

Vertical Pinterest graphic with five points on fixing the Flutter signed in debug mode Play upload error
Pinterest pin: Flutter debug-mode fix.

FAQ

How do I fix "signed in debug mode" in Flutter?

Create an upload keystore, add android/key.properties, load it in android/app/build.gradle.kts, change the release build type to signingConfigs.getByName("release"), then run flutter clean and flutter build appbundle. Upload the new bundle.

Why is my Flutter release build signed with the debug key?

New Flutter projects ship with the release build type pointing at the debug signing config so flutter run --release works out of the box. It stays that way until you add your own release signing config.

Where does key.properties go in a Flutter project?

In the android folder, as android/key.properties, because the Gradle script loads it with rootProject.file. Keep it out of source control.

Do I need flutter clean after changing the signing config?

Often, yes. The Flutter guide says you might need flutter clean after changing the Gradle file so that cached builds don't affect signing.

Sources