{"record":{"id":"b33d7113eaf239a7","repo":"material-components/material-components-android","slug":"invalid-axis-axis","errorCode":null,"errorMessage":"Invalid axis: > axis <","messagePattern":"Invalid axis: > axis <","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/transition/MaterialSharedAxis.java","lineNumber":116,"sourceCode":"  public int getAxis() {\n    return axis;\n  }\n\n  public boolean isForward() {\n    return forward;\n  }\n\n  private static VisibilityAnimatorProvider createPrimaryAnimatorProvider(\n      @Axis int axis, boolean forward) {\n    switch (axis) {\n      case X:\n        return new SlideDistanceProvider(forward ? Gravity.END : Gravity.START);\n      case Y:\n        return new SlideDistanceProvider(forward ? Gravity.BOTTOM : Gravity.TOP);\n      case Z:\n        return new ScaleProvider(forward);\n      default:\n        throw new IllegalArgumentException(\"Invalid axis: \" + axis);\n    }\n  }\n\n  private static VisibilityAnimatorProvider createSecondaryAnimatorProvider() {\n    return new FadeThroughProvider();\n  }\n\n  @AttrRes\n  @Override\n  int getDurationThemeAttrResId(boolean appearing) {\n    return DEFAULT_THEMED_DURATION_ATTR;\n  }\n\n  @AttrRes\n  @Override\n  int getEasingThemeAttrResId(boolean appearing) {\n    return DEFAULT_THEMED_EASING_ATTR;\n  }","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/transition/MaterialSharedAxis.java#L98-L134","documentation":"MaterialSharedAxis.createPrimaryAnimatorProvider (MaterialSharedAxis.java:116) maps the axis constant to the primary motion: X slides horizontally, Y slides vertically, Z scales. The @Axis annotation allows only X (0), Y (1), Z (2); any other int reaches the default branch and throws IllegalArgumentException when the shared-axis transition is created.","triggerScenarios":"Calling MaterialSharedAxis(MaterialSharedAxis.XYZ_SOMETHING, true) with an invalid int — typically a hardcoded number or a constant imported from the wrong class; constructing MaterialSharedAxis(axis, true) where axis came from serialization/bundles unchecked.","commonSituations":"Numeric literals instead of MaterialSharedAxis.X/Y/Z; constants mixed up with gravity or fade-mode values; code-generation or JSON-driven transition config that feeds raw ints.","solutions":["Use MaterialSharedAxis.X, MaterialSharedAxis.Y, or MaterialSharedAxis.Z when constructing the transition.","Validate dynamic axis values: clamp or reject anything outside 0..2.","Annotate your own config-layer parameter with @Axis for lint-time enforcement."],"exampleFix":"// before\nMaterialSharedAxis axis = new MaterialSharedAxis(4, true); // invalid\n\n// after\nMaterialSharedAxis axis = new MaterialSharedAxis(MaterialSharedAxis.Z, true);","handlingStrategy":"validation","validationCode":"static boolean isValidSharedAxis(int axis) {\n  return axis == MaterialSharedAxis.X || axis == MaterialSharedAxis.Y || axis == MaterialSharedAxis.Z;\n}\nif (!isValidSharedAxis(cfgAxis)) throw new IllegalArgumentException(\"axis must be X, Y or Z\");\nnew MaterialSharedAxis(cfgAxis, true);","typeGuard":"static @Axis int coerceAxis(int a) {\n  return isValidSharedAxis(a) ? a : MaterialSharedAxis.Y;\n}","tryCatchPattern":null,"preventionTips":["Construct MaterialSharedAxis only with its X/Y/Z constants.","Keep transition config ints typed (dedicated fields per knob) to prevent constant mix-ups.","Validate deserialized config in one choke point before creating transitions."],"tags":["android","material-components","shared-axis","transition","enum-validation"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}