jax-ml/jax · error · TypeError

No attribute handler defined for type: {type(val)}

Error message

No attribute handler defined for type: {type(val)}

What it means

The attribute counterpart of constant lowering: when a value must become an MLIR attribute (e.g. for operation attributes during custom lowering rules), JAX looks up a registered attribute handler. If none exists for the type and the object has no __jax_array__, it raises this TypeError.

Source

Thrown at jax/_src/interpreters/mlir.py:491

  return ir.ArrayAttr.get([ir_attribute(v) for v in val])

register_attribute_handler(list, _sequence_attribute_handler)
register_attribute_handler(tuple, _sequence_attribute_handler)
register_attribute_handler(ir.Attribute, lambda x: x)
register_attribute_handler(ir.Type, lambda x: x)

def ir_attribute(val: Any) -> ir.Attribute:
  """Convert a Python value to an MLIR attribute."""
  for t in type(val).__mro__:
    handler = _attribute_handlers.get(t)
    if handler:
      out = handler(val)
      assert isinstance(out, ir.Attribute), (type(val), out)
      return out
  m = getattr(val, '__jax_array__', None)
  if m is not None:
    return ir_attribute(m())
  raise TypeError(f"No attribute handler defined for type: {type(val)}")

# Source locations

def get_canonical_source_file(file_name: str, caches: TracebackCaches) -> str:
  canonical_file_name = caches.canonical_name_cache.get(file_name, None)
  if canonical_file_name is not None:
    return canonical_file_name

  pattern = config.hlo_source_file_canonicalization_regex.value
  if pattern:
    file_name = re.sub(pattern, '', file_name)
  caches.canonical_name_cache[file_name] = file_name
  return file_name


class HasTracebackCaches(Protocol):
  @property
  def traceback_caches(self) -> TracebackCaches:

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Convert the value to a numpy/JAX array or a supported scalar before it reaches ir_attribute
  2. Implement __jax_array__ on your class
  3. Register an attribute handler for your type (mirroring register_constant_handler)
  4. If you are a user (not a lowering author), check for accidentally passing custom objects into jitted code paths that feed attributes

Example fix

# before
ctx.ir_attribute(my_obj)  # TypeError: No attribute handler

# after
ctx.ir_attribute(np.asarray(my_obj.value))
Defensive patterns

Strategy: validation

Validate before calling

def to_attribute_safe(v):
    if hasattr(v, '__jax_array__'):
        return v
    if not isinstance(v, (np.ndarray, np.generic, bool, int, float, complex, tuple, list)):
        return np.asarray(v)
    return v

Try / catch

try:
    attr = mlir.ir_attribute(val)
except TypeError as e:
    if 'No attribute handler' in str(e):
        attr = mlir.ir_attribute(np.asarray(val))
    else:
        raise

Prevention

When it happens

Trigger: Writing a custom primitive/lowering rule whose impl calls mlir.ir_attribute on an unsupported Python object; passing non-array metadata (strings handled separately, but e.g. custom enums, objects) where an array-like attribute is expected in _lowering_op or composite lowering.

Common situations: Library authors implementing custom JAX primitives (esp. with composite/custom lowering APIs); version upgrades where attribute handler registration for a type was removed or moved; passing dicts/sequences whose leaves contain unsupported types recursively.

Related errors


AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27). Data as JSON: /api/errors/dd008b0f2f49ee15. Report an issue: GitHub.