{"record":{"id":"22e89a6768443a17","repo":"microg/GmsCore","slug":"not-a-string-type","errorCode":null,"errorMessage":"Not a String type","messagePattern":"Not a String type","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-phenotype/src/main/java/com/google/android/gms/phenotype/Flag.java","lineNumber":89,"sourceCode":"        throw new IllegalArgumentException(\"Not a long type\");\n    }\n\n    public boolean getBool() {\n        if (dataType == DATA_TYPE_BOOL)\n            return boolValue;\n        throw new IllegalArgumentException(\"Not a boolean type\");\n    }\n\n    public double getDouble() {\n        if (dataType == DATA_TYPE_DOUBLE)\n            return doubleValue;\n        throw new IllegalArgumentException(\"Not a double type\");\n    }\n\n    public String getString() {\n        if (dataType == DATA_TYPE_STRING)\n            return stringValue;\n        throw new IllegalArgumentException(\"Not a String type\");\n    }\n\n    public byte[] getBytes() {\n        if (dataType == DATA_TYPE_BYTES)\n            return bytesValue;\n        throw new IllegalArgumentException(\"Not a bytes type\");\n    }\n\n    public static final int DATA_TYPE_LONG = 1;\n    public static final int DATA_TYPE_BOOL = 2;\n    public static final int DATA_TYPE_DOUBLE = 3;\n    public static final int DATA_TYPE_STRING = 4;\n    public static final int DATA_TYPE_BYTES = 5;\n\n    public static final Creator<Flag> CREATOR = findCreator(Flag.class);\n}\n","sourceCodeStart":71,"sourceCodeEnd":106,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-phenotype/src/main/java/com/google/android/gms/phenotype/Flag.java#L71-L106","documentation":"Flag.getString() throws IllegalArgumentException(\"Not a String type\") when the flag's dataType is not DATA_TYPE_STRING. Flag is a tagged union, and the string accessor refuses to return stringValue unless the discriminator matches, preventing silent misreads of non-string flags.","triggerScenarios":"Calling Flag.getString() on a Flag whose dataType is DATA_TYPE_LONG (1), DATA_TYPE_BOOL (2), DATA_TYPE_DOUBLE (3), or DATA_TYPE_BYTES (5) instead of DATA_TYPE_STRING (4).","commonSituations":"Treating a numeric/boolean experiment flag as a string (e.g. for feature parameters); server-side flag retyped from string to long; blanket flag-to-map conversion code that calls getString() on every entry.","solutions":["Guard with flag.getDataType() == Flag.DATA_TYPE_STRING before calling getString()","In generic conversion code, switch over DATA_TYPE_* and convert each type to string explicitly (String.valueOf / Arrays.toString)","Verify the server-side flag is still a string type","Catch IllegalArgumentException when deserializing untrusted flag data"],"exampleFix":"// before\nString s = flag.getString();\n// after\nString s = flag.getDataType() == Flag.DATA_TYPE_STRING ? flag.getString() : null;","handlingStrategy":"type-guard","validationCode":"if (flag.getDataType() != Flag.DATA_TYPE_STRING) { throw new IllegalStateException(\"flag is not a string: \" + flag.getDataType()); }","typeGuard":"static boolean isStringFlag(Flag f) { return f != null && f.getDataType() == Flag.DATA_TYPE_STRING; }","tryCatchPattern":"try { String v = flag.getString(); } catch (IllegalArgumentException e) { log.warn(\"Flag type mismatch\", e); v = null; }","preventionTips":["Check dataType == DATA_TYPE_STRING before getString()","In generic conversions, stringify each type via its own getter, not getString() unconditionally","Never assume config values are strings across library or protocol changes","Handle nulls and unexpected types when building flag maps"],"tags":["android","phenotype","type-mismatch","flags"],"backgroundTag":"type-mismatch","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}