airbnb/epoxy · error · EpoxyProcessorException

Expected this to be a variable or method $this

Error message

Expected this to be a variable or method $this

What it means

expectName is an extension on XElement that extracts a name for variables, methods, and type elements. Any other XElement kind has no name to expect, so the getter throws EpoxyProcessorException (carrying the element) to fail annotation processing with a precise diagnostic instead of returning a bogus name.

Solutions

  1. Only call expectName after confirming the element kind (is XVariableElement / XMethodElement / XTypeElement).
  2. Handle the element kind explicitly with a when and skip/derive names for unsupported kinds instead of calling expectName.
  3. If triggered by a legit Epoxy feature, update epoxy-processor — the when in expectName may need the new element kind.
  4. Use the element carried in EpoxyProcessorException to locate the offending declaration and fix the model code.

Example fix

// before
val name = element.expectName() // throws for unsupported kinds

// after
val name = when (element) {
  is XVariableElement, is XMethodElement, is XTypeElement -> element.expectName
  else -> return // or derive a name another way
}
Defensive patterns

Strategy: type-guard

Type guard

fun XElement.nameIfSupported(): String? = when (this) {
  is XVariableElement -> this.name
  is XMethodElement -> this.name
  is XTypeElement -> this.name
  else -> null
}

Prevention

When it happens

Trigger: Processor code (e.g. attribute/hoisting logic) calls element.expectName on an XElement that is a variable, method, or type element — but encounters a different kind such as an executable's type parameter, a package element, or an unexpected modelin element subclass.

Common situations: New Epoxy model types/annotations whose processed elements aren't variables/methods/types (e.g. nested annotations); custom processor extensions calling expectName too broadly; library upgrades changing XProcessing element wrappers.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/770771b05b678416. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-processor/src/main/java/com/airbnb/epoxy/processor/XProcessingUtils.kt:261

val XHasModifiers.javacModifiers: Set<Modifier>
    get() {
        return setOfNotNull(
            if (isPublic()) Modifier.PUBLIC else null,
            if (isProtected()) Modifier.PROTECTED else null,
            if (isAbstract()) Modifier.ABSTRACT else null,
            if (isPrivate()) Modifier.PRIVATE else null,
            if (isStatic()) Modifier.STATIC else null,
            if (isFinal()) Modifier.FINAL else null,
            if (isTransient()) Modifier.TRANSIENT else null,
        )
    }

val XElement.expectName: String
    get() = when (this) {
        is XVariableElement -> this.name
        is XMethodElement -> this.name
        is XTypeElement -> this.name
        else -> throw EpoxyProcessorException(
            "Expected this to be a variable or method $this",
            element = this
        )
    }

fun XType.isSubTypeOf(otherType: XType): Boolean {
    // Using the normal "isAssignableFrom" on XType doesn't always work correctly or predictably
    // with generics, so when we just want to check if something is a subclass without considering
    // that this is the simplest approach.
    // This is especially because we generally just use this to check class type hierarchies, not
    // parameter/field types.
    return otherType.rawType.isAssignableFrom(this)
}

fun XTypeElement.isSubTypeOf(otherType: XTypeElement): Boolean {
    return type.isSubTypeOf(otherType.type)
}

View on GitHub (pinned to e45bd3a61f)