skip to content

On a new laptop, flutter doctor marks the Android toolchain [!] with 'Android license status unknown' — how do you diagnose and fix it with the Flutter tool?

level: seniorimportance: should knowfreq 42%

answer

  1. licence check shells out
  2. sdkmanager lives in cmdline-tools
  3. needs a runnable JDK
  4. Java binary at: in -v
  5. flutter doctor --android-licenses

basics

~20 s

Doctor checks licences by running the SDK's sdkmanager --licenses with the JDK it found; status unknown means that run failed. Install cmdline-tools, point Flutter at a working JDK, then run flutter doctor --android-licenses and accept.

solid answer

~40 s

The licence sub-check runs `sdkmanager --licenses` from the Android SDK's `cmdline-tools`, using the JDK Flutter discovered, and parses its output into all, some, none or unknown. **Unknown** means the tool could not run or its output could not be read. So I run `flutter doctor -v` and read the Android section: is the SDK where I expect, does it say `cmdline-tools component is missing`, and what does `Java binary at:` report? I install cmdline-tools if needed, point Flutter at a suitable JDK with `flutter config --jdk-dir` if the found one is wrong, then run `flutter doctor --android-licenses`, which runs `sdkmanager --licenses` interactively so I accept each licence. A final `flutter doctor` should show the section as `[✓]` with `All Android licenses accepted.`

code

bash · 5 lines
bash
flutter doctor -v                       # read the Android section: SDK path, cmdline-tools, 'Java binary at:'
flutter config --android-sdk "$HOME/Library/Android/sdk"   # only if doctor found the wrong SDK
flutter config --jdk-dir "/path/to/jdk-17"                 # only if the found JDK cannot run sdkmanager
flutter doctor --android-licenses       # runs sdkmanager --licenses; answer y to each licence
flutter doctor                          # Android toolchain should now be [✓]

go deeper

for a junior

Remember the fix command, flutter doctor --android-licenses, and that you must answer y to each licence it shows.

for a middle

Explain that the licence check shells out to sdkmanager from cmdline-tools using the JDK Flutter found, and what each of the four states means.

for a senior

Diagnose from doctor -v: SDK location, cmdline-tools presence, the JDK source line, and the too-old-JDK error, then fix in the right order before accepting licences.

for a principal

Decide how a team avoids this on every new machine: a documented JDK and cmdline-tools baseline, or a scripted setup, versus letting each developer rediscover it.

## The scenario A developer sets up a new laptop: Flutter SDK extracted and on `PATH`, Android Studio installed. `flutter doctor` shows `[!] Android toolchain` with a line like `Android license status unknown. Run flutter doctor --android-licenses to accept the SDK licenses.` Running that suggested command sometimes fixes it immediately and sometimes fails with a second error. Knowing what the check actually does turns this from trial and error into a short diagnosis. ## How Flutter checks Android licences The Android toolchain section is a **grouped validator**: the main Android check plus an **Android licence sub-validator**. The licence sub-check: 1. Gives up early, reporting nothing useful, if there is no Android SDK, no build-tools, a malformed SDK, or **no JDK that runs**. 2. Locates `sdkmanager` inside the SDK's **`cmdline-tools`** component. If it is not there or cannot be executed, the status is **unknown**. 3. Runs `sdkmanager --licenses` with the **JDK Flutter discovered** in its environment, answers `n` to any prompt, and parses the output. 4. Maps the result to one of four states: | State | Doctor message | Marker | |---|---|---| | all | `All Android licenses accepted.` | `[✓]` | | some | `Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses` | `[!]` | | none | `Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses` | `[!]` | | unknown | `Android license status unknown.` plus the same command | `[!]` | When newer command-line tools print output Flutter cannot parse, it falls back to looking for non-empty files in the SDK's `licenses` directory, which is where accepted licences are recorded. ## Diagnosing step by step 1. **Run `flutter doctor -v`.** The verbose Android section prints the SDK location, the build-tools version, whether `cmdline-tools` is present, and the `Java binary at:` line with the JDK's source (Flutter config, Android Studio's bundled JDK, `JAVA_HOME`, or `PATH`). 2. **Check the SDK location.** If doctor cannot find the SDK, or finds a different one than Android Studio uses, set it with `flutter config --android-sdk <path>`; Flutter otherwise reads `ANDROID_HOME` (and the deprecated `ANDROID_SDK_ROOT`). 3. **Check `cmdline-tools`.** A fresh Android Studio install does not always include it. Doctor then reports `cmdline-tools component is missing` as an error. Without it there is no `sdkmanager`, so the licence status can only be unknown; install the component from Android Studio's SDK manager UI. 4. **Check the JDK.** `sdkmanager` is a Java program. If the found JDK is too old for the installed command-line tools, the run fails with an `UnsupportedClassVersionError` and doctor explains that the Java binary is too out of date. Point Flutter at a suitable JDK with `flutter config --jdk-dir <path>`. 5. **Accept the licences.** `flutter doctor --android-licenses` runs `sdkmanager --licenses` interactively with your terminal attached; review and answer `y` to each licence. 6. **Re-run `flutter doctor`.** The section should now be `[✓]`. ## Why this order matters - Running `--android-licenses` first, while `cmdline-tools` is missing, only produces `Android sdkmanager not found. Update to the latest Android SDK and ensure that the cmdline-tools are installed to resolve this.` - Setting `JAVA_HOME` alone may not change anything: Flutter prefers **Android Studio's bundled JDK over `JAVA_HOME`**, and a `jdk-dir` in Flutter's config over both. - Unaccepted licences are not cosmetic. Gradle refuses to download missing SDK packages until the licences are accepted, so the first Android build fails. ## What belongs elsewhere `sdkmanager`, `adb` and emulator management are Android SDK tools with their own topic; here they matter only as what `flutter doctor` calls. A licence problem on a CI machine is handled the same way, but pre-accepting licences in a pipeline image is a CI concern.

  • Why might setting JAVA_HOME not change the JDK that flutter doctor reports?
    Flutter searches for a JDK in a fixed order: a `jdk-dir` in its own config first, then the JDK bundled with the latest Android Studio, then `JAVA_HOME`, then `java` on `PATH`. With Android Studio installed, its JDK wins over `JAVA_HOME`. `flutter doctor -v` states the source next to `Java binary at:`; use `flutter config --jdk-dir` to override.
  • What is the difference between 'licenses not accepted' and 'license status unknown'?
    Not accepted means `sdkmanager --licenses` ran and reported unaccepted licences, so running `flutter doctor --android-licenses` and accepting them fixes it. Unknown means Flutter could not get an answer: `sdkmanager` is missing (no `cmdline-tools`), would not execute, or failed under the chosen JDK. Fix the tool or the JDK first.
  • Does an unaccepted licence only affect doctor's output?
    No. Gradle will not download missing Android SDK packages until their licences are accepted, so the first Android build on that machine fails. The `[!]` is a warning about a real build failure waiting to happen.

saying these in an interview costs you the question

  • Runs flutter doctor --android-licenses repeatedly without checking cmdline-tools
  • Assumes JAVA_HOME always decides which JDK Flutter uses
  • Deletes and reinstalls the Flutter SDK to fix an Android licence warning
  • Thinks unaccepted licences only affect doctor, not Gradle builds
  • Believes Flutter bundles its own copy of sdkmanager