keras-team/keras · error · ValueError
Unexpected object from deserialization, expected a layer or…
Error message
Unexpected object from deserialization, expected a layer or operation, got a {type(layer)} What it means
Guard during Functional model deserialization: after instantiating an entry from the saved layer config, the object is not an Operation/Layer (e.g. the class_name resolved to a loss, metric, or plain function because of a custom_objects mapping mistake). The graph reconstruction only knows how to wire Layer/Operation nodes, so anything else is rejected.
Solutions
- Check custom_objects / registrations: the layer name in the config must map to an actual Layer (or Operation) subclass
- Ensure a custom class registered with the same name didn't shadow the layer
- Verify the serialized model wasn't produced with a mismatched Keras version
Defensive patterns
Strategy: type-guard
When it happens
Trigger: Thrown at keras/src/models/functional.py:573 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25).
Data as JSON: /api/errors/38107ede870e8e0e.
Report an issue: GitHub.
Appendix: source
Thrown at keras/src/models/functional.py:573
Args:
layer_data: layer config dict.
"""
layer_name = layer_data["name"]
# Instantiate layer.
if "module" not in layer_data:
# Legacy format deserialization (no "module" key)
# used for H5 and SavedModel formats
layer = saving_utils.model_from_config(
layer_data, custom_objects=custom_objects
)
else:
layer = serialization_lib.deserialize_keras_object(
layer_data, custom_objects=custom_objects
)
if not isinstance(layer, Operation):
raise ValueError(
"Unexpected object from deserialization, expected a layer or "
f"operation, got a {type(layer)}"
)
created_layers[layer_name] = layer
# Gather layer inputs.
inbound_nodes_data = layer_data["inbound_nodes"]
for node_data in inbound_nodes_data:
# We don't process nodes (i.e. make layer calls)
# on the fly because the inbound node may not yet exist,
# in case of layer shared at different topological depths
# (e.g. a model such as A(B(A(B(x)))))
add_unprocessed_node(layer, node_data)
# Extract config used to instantiate Functional model from the config. The
# remaining config will be passed as keyword arguments to the Model
# constructor.
functional_config = {}View on GitHub (pinned to 7a34a03db6)