{"record":{"id":"b1b5e335d6263ab4","repo":"microg/GmsCore","slug":"versionpolicy-returned-invalid-code","errorCode":null,"errorMessage":"VersionPolicy returned invalid code:","messagePattern":"VersionPolicy returned invalid code:","errorType":"exception","errorClass":"DynamiteModule.LoadingException","httpStatus":null,"severity":"error","filePath":"play-services-basement/src/main/java/com/google/android/gms/dynamite/DynamiteModule.java","lineNumber":146,"sourceCode":"    }\n\n    @NonNull\n    public static DynamiteModule load(@NonNull Context context, @NonNull VersionPolicy policy, @NonNull String moduleId) throws LoadingException {\n        Context applicationContext = context.getApplicationContext();\n        if (applicationContext == null) throw new LoadingException(\"null application Context\", null);\n        try {\n            VersionPolicy.SelectionResult result = policy.selectModule(context, moduleId, VersionPolicy.IVersions.Default);\n            Log.i(TAG, \"Considering local module \" + moduleId + \":\" + result.localVersion + \" and remote module \" + moduleId + \":\" + result.remoteVersion);\n            switch (result.selection) {\n                case NONE:\n                    throw new LoadingException(\"No acceptable module \" + moduleId + \" found. Local version is \" + result.localVersion + \" and remote version is \" + result.remoteVersion + \".\");\n                case LOCAL:\n                    Log.i(TAG, \"Selected local version of \" + moduleId);\n                    return new DynamiteModule(context);\n                case REMOTE:\n                    throw new UnsupportedOperationException();\n                default:\n                    throw new LoadingException(\"VersionPolicy returned invalid code:\" + result.selection);\n            }\n        } catch (LoadingException loadingException) {\n            throw loadingException;\n        } catch (Throwable e) {\n            throw new LoadingException(\"Failed to load remote module.\", e);\n        }\n    }\n\n    @NonNull\n    public IBinder instantiate(@NonNull String className) throws LoadingException {\n        try {\n            return (IBinder) this.moduleContext.getClassLoader().loadClass(className).newInstance();\n        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | RuntimeException e) {\n            throw new LoadingException(\"Failed to instantiate module class: \" + className, e);\n        }\n    }\n}\n","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-basement/src/main/java/com/google/android/gms/dynamite/DynamiteModule.java#L128-L164","documentation":"DynamiteModule.load switches on the VersionPolicy.SelectionResult.selection value. If a policy returns a selection code that is not NONE, LOCAL, or REMOTE, the default branch throws LoadingException('VersionPolicy returned invalid code:'). This indicates a buggy or incompatible custom VersionPolicy.","triggerScenarios":"Supplying a custom VersionPolicy (or a SelectionResult built by one) that sets an out-of-range/unknown selection constant; version mismatch where a policy written against a different library version returns an unrecognized code.","commonSituations":"Hand-rolled VersionPolicy implementations copied from older gms versions; mocked SelectionResult in tests with an unset/garbage selection field; binary-incompatible library versions.","solutions":["Fix the custom VersionPolicy to only set selection to SelectionResult.Selection.NONE, .LOCAL, or .REMOTE","Use the built-in policies (PREFER_REMOTE, PREFER_HIGHEST_OR_LOCAL, PREFER_LOCAL) instead of custom ones","Ensure SelectionResult.selection is always explicitly assigned before returning it from selectModule","Catch LoadingException and fall back to default module-loading behavior"],"exampleFix":"// before\nresult.selection = 7; // unknown code -> throws\n// after\nresult.selection = VersionPolicy.SelectionResult.Selection.LOCAL;","handlingStrategy":"validation","validationCode":"// if you supply a custom policy, assert its output before load\nVersionPolicy.SelectionResult r = policy.selectModule(ctx, moduleId, versions);\nboolean ok = r.selection == VersionPolicy.SelectionResult.Selection.NONE\n          || r.selection == VersionPolicy.SelectionResult.Selection.LOCAL\n          || r.selection == VersionPolicy.SelectionResult.Selection.REMOTE;\nif (!ok) { /* fix policy, don't call load */ }","typeGuard":null,"tryCatchPattern":"try {\n    DynamiteModule m = DynamiteModule.load(ctx, myPolicy, moduleId);\n} catch (DynamiteModule.LoadingException e) {\n    // invalid selection code — switch to a built-in policy\n    m = DynamiteModule.load(ctx, DynamiteModule.PREFER_HIGHEST_OR_LOCAL, moduleId);\n}","preventionTips":["Only return NONE/LOCAL/REMOTE from custom VersionPolicies","Always initialize SelectionResult.selection before returning","Prefer built-in VersionPolicy constants over hand-rolled implementations","Keep gms library versions consistent so policy enums match"],"tags":["android","dynamite","version-policy","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}