{"record":{"id":"b1e1866ce99043dc","repo":"material-components/material-components-android","slug":"invalid-axis-axis-b1e186","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/platform/MaterialSharedAxis.java","lineNumber":121,"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":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/transition/platform/MaterialSharedAxis.java#L103-L139","documentation":"MaterialSharedAxis builds its primary animator from a fixed @Axis enum whose only legal values are MaterialSharedAxis.X (0), Y (1) and Z (2). createPrimaryAnimatorProvider switches on the axis and any other int falls into the default branch, throwing IllegalArgumentException('Invalid axis: ' + axis). This is a fail-fast guard against typos and against axis values read from theme attributes or serialized state that are not part of the enum.","triggerScenarios":"Calling new MaterialSharedAxis(context, attr, axis) or MaterialSharedAxis.create(context, attr, axis) with an int outside 0..2; inflating a transition from XML where the app:transitionMotionPath...-style axis attribute was hand-edited to 3+; computing the axis at runtime from an unchecked config value or deep-link extra and passing it through.","commonSituations":"Storing the axis in a settings/preferences int and mapping it incorrectly; copy-pasting example code that uses a made-up constant; proguard/R8 shrinking or ordinal misuse (e.g., axis = someEnum.values().length); deserializing the axis from JSON/analytics payloads.","solutions":["Pass only the class constants: MaterialSharedAxis.X, MaterialSharedAxis.Y, or MaterialSharedAxis.Z.","If the axis comes from external input, clamp/map it first: int axis = parseAxis(raw); if (axis < 0 || axis > 2) axis = MaterialSharedAxis.X;","Check the XML transition definition for a hand-typed axis value and replace it with @enum (linear|arc|... axis enums: 0/1/2) or the corresponding int.","Verify the value against the @Axis int... annotation contract in the source before constructing the transition."],"exampleFix":"// before\nint axis = preferences.getInt(\"nav_axis\", 3); // out of range\ntransition = new MaterialSharedAxis(getContext(), attr, axis);\n\n// after\nint raw = preferences.getInt(\"nav_axis\", MaterialSharedAxis.X);\nint axis = (raw >= MaterialSharedAxis.X && raw <= MaterialSharedAxis.Z)\n    ? raw : MaterialSharedAxis.X;\ntransition = new MaterialSharedAxis(getContext(), attr, axis);","handlingStrategy":"validation","validationCode":"static final int[] VALID_AXES = {\n    MaterialSharedAxis.X, MaterialSharedAxis.Y, MaterialSharedAxis.Z};\n\n@MaterialSharedAxis.Axis int sanitizeAxis(int raw) {\n  for (int valid : VALID_AXES) {\n    if (raw == valid) return raw;\n  }\n  return MaterialSharedAxis.X; // or throw on untrusted input\n}","typeGuard":"static boolean isValidAxis(int axis) {\n  return axis == MaterialSharedAxis.X\n      || axis == MaterialSharedAxis.Y\n      || axis == MaterialSharedAxis.Z;\n}","tryCatchPattern":"try {\n  transition = new MaterialSharedAxis(context, attr, axis);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Invalid axis\")) {\n    transition = new MaterialSharedAxis(context, attr, MaterialSharedAxis.X);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always construct the axis from MaterialSharedAxis.X/Y/Z constants, never raw ints.","Treat axes from preferences, deep links, or payloads as untrusted; whitelist them.","Add a lint/test assert when mapping an enum to the axis int."],"tags":["android","material-components","transition","shared-axis","validation"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}