alibaba/ARouter · error · RuntimeException

The field '<fieldName>' is null, in class '<className>!

Error message

The field '<fieldName>' is null, in class '<className>!

What it means

When an @Autowired field is declared with required = true, the generated injection code throws RuntimeException at runtime if the field is still null after injection. This is a fail-fast validator so missing navigation arguments surface immediately instead of causing NPEs later.

Source

Thrown at arouter-compiler/src/main/java/com/alibaba/android/arouter/compiler/processor/AutowiredProcessor.java:171

                                    "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
                                    ARouterClass,
                                    ClassName.get(element.asType())
                            );
                        } else {    // use byName
                            // Getter
                            injectMethodBuilder.addStatement(
                                    "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()",
                                    ClassName.get(element.asType()),
                                    ARouterClass,
                                    fieldConfig.name()
                            );
                        }

                        // Validator
                        if (fieldConfig.required()) {
                            injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
                            injectMethodBuilder.addStatement(
                                    "throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", ClassName.get(parent));
                            injectMethodBuilder.endControlFlow();
                        }
                    } else {    // It's normal intent value
                        String paramName = StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name();
                        int type = typeUtils.typeExchange(element);

                        injectMethodBuilder.beginControlFlow("if (null != bundle && bundle.containsKey($S))", paramName);
                        if (type == TypeKind.OBJECT.ordinal()) {
                            injectMethodBuilder.beginControlFlow("if (null != serializationService)");
                            TypeName fieldType = TypeName.get(element.asType());
                            String valueName = fieldName + "Value";
                            injectMethodBuilder.addStatement(
                                    "$T " + valueName + " = serializationService.parseObject(bundle.getString($S), new $T<$T>(){}.getType())",
                                    fieldType,
                                    paramName,
                                    TypeWrapperClass,
                                    fieldType
                            );

View on GitHub (pinned to 84f451d244)

Solutions

  1. Pass the required parameter at every navigation call site: ARouter.getInstance().build(path).withString("name", value)
  2. Make the field optional by removing required = true if it can legitimately be absent
  3. For external entry points, ensure the intent extras carry all required keys, or route external opens through ARouter
  4. Guard nullable fields in code and log the missing key to find the offending caller

Example fix

// before
ARouter.getInstance().build("/user/detail").navigation(); // RuntimeException: field 'userId' is null
// after
ARouter.getInstance().build("/user/detail")
        .withString("userId", userId)
        .navigation();
Defensive patterns

Strategy: validation

Validate before calling

// before navigating, ensure required params are supplied
public static void navToUserDetail(String userId) {
    if (userId == null || userId.isEmpty()) {
        Log.w(TAG, "userId required for /user/detail");
        return;
    }
    ARouter.getInstance().build("/user/detail").withString("userId", userId).navigation();
}

Try / catch

try {
    ARouter.getInstance().build(path).withString("userId", userId).navigation();
} catch (RuntimeException e) {
    Log.e(TAG, "Missing required autowired field", e);
}

Prevention

When it happens

Trigger: Navigating to an Activity/Fragment without putting the required parameter: ARouter.with(...).navigation() omitting withString/withInt for a field marked @Autowired(required = true), or opening the target from outside ARouter (deep link, notification) without the extras.

Common situations: Deep links or push intents that skip the ARouter builder and its typed params; refactoring a route name and forgetting a call site's withString; optional-in-practice params wrongly marked required = true.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of alibaba/ARouter@84f451d244 (2026-09-06). Data as JSON: /api/errors/84454b61c7dbbc88. Report an issue: GitHub.