microg/GmsCore · error · IllegalArgumentException

granularity {granularity} must be a Granularity.GRANULARITY_

Error message

granularity {granularity} must be a Granularity.GRANULARITY_* constant

What it means

GranularityUtil.checkValidGranularity validates that a granularity int is one of the Granularity.GRANULARITY_* constants (allowed values checked by isValidGranularity). Any other integer is rejected with an IllegalArgumentException before the value reaches the location request.

Source

Thrown at play-services-location/src/main/java/org/microg/gms/location/GranularityUtil.java:25

import com.google.android.gms.location.Granularity;
import com.google.android.gms.location.Priority;

public class GranularityUtil {
    public static boolean isValidGranularity(int granularity) {
        switch (granularity) {
            default:
                return false;
            case Granularity.GRANULARITY_PERMISSION_LEVEL:
            case Granularity.GRANULARITY_COARSE:
            case Granularity.GRANULARITY_FINE:
                return true;
        }
    }

    public static int checkValidGranularity(int granularity) {
        if (!isValidGranularity(granularity)) {
            throw new IllegalArgumentException("granularity " + granularity + " must be a Granularity.GRANULARITY_* constant");
        }
        return granularity;
    }

    public static String granularityToString(int granularity) {
        switch (granularity) {
            case Granularity.GRANULARITY_PERMISSION_LEVEL:
                return "GRANULARITY_PERMISSION_LEVEL";
            case Granularity.GRANULARITY_COARSE:
                return "GRANULARITY_COARSE";
            case Granularity.GRANULARITY_FINE:
                return "GRANULARITY_FINE";
            default:
                throw new IllegalArgumentException();
        }
    }
}

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Use Granularity.GRANULARITY_PERMISSION_LEVEL, Granularity.GRANULARITY_COARSE, or Granularity.GRANULARITY_FINE constants only
  2. Do not bitwise-combine granularity constants; they are mutually exclusive enum values
  3. Verify the source of the int (settings/intent extras) and clamp/default it before validation

Example fix

// before
int granularity = 2; // arbitrary
checkValidGranularity(granularity);
// after
int granularity = Granularity.GRANULARITY_FINE;
checkValidGranularity(granularity);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isKnownGranularity(int g) {
    return g == Granularity.GRANULARITY_PERMISSION_LEVEL
        || g == Granularity.GRANULARITY_COARSE
        || g == Granularity.GRANULARITY_FINE;
}

Try / catch

try { GranularityUtil.checkValidGranularity(g); } catch (IllegalArgumentException e) { g = Granularity.GRANULARITY_PERMISSION_LEVEL; }

Prevention

When it happens

Trigger: Passing an arbitrary int to checkValidGranularity (directly or via LocationRequest building paths) that is not a valid Granularity constant, e.g. 0, 3, or a bitfield combining constants.

Common situations: Hard-coding a granularity value instead of referencing Granularity.GRANULARITY_PERMISSION_LEVEL / GRANULARITY_COARSE / GRANULARITY_FINE; confusing priority constants with granularity constants; migrating from old LocationRequest flags.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/dfd9d49cb35c32a3. Report an issue: GitHub.