keras-team/keras · critical · ValueError

Layer '{self.name}' was never built and thus it doesn't have

Error message

Layer '{self.name}' was never built and thus it doesn't have any variables. However the weights file lists {len(store.keys())} variables for this layer.
In most cases, this error indicates that either:

1. The layer is owned by a parent layer that implements a `build()` method, but calling the parent's `build()` method did NOT create the state of the child layer '{self.name}'. A `build()` method must create ALL state for the layer, including the state of any children layers.

2. You need to implement the `def build_from_config(self, config)` method on layer '{self.name}', to specify how to rebuild it during loading. In this case, you might also want to implement the method that generates the build config at saving time, `def get_build_config(self)`. The method `build_from_config()` is meant to create the state of the layer (i.e. its variables) upon deserialization.

What it means

Raised when loading weights into a Keras layer whose variable count doesn't match the weights file: the layer has zero variables because it was never built, yet the checkpoint lists variables for it. Keras builds layer state lazily in build(), so a layer with no variables at load time means its state was never created during deserialization. The message points at two root causes: a parent layer's build() that fails to create child state, or missing build_from_config()/get_build_config() support for rebuilding during loading.

Source

Thrown at keras/src/layers/convolutional/base_conv.py:395

                "activity_regularizer": regularizers.serialize(
                    self.activity_regularizer
                ),
                "kernel_constraint": constraints.serialize(
                    self.kernel_constraint
                ),
                "bias_constraint": constraints.serialize(self.bias_constraint),
            }
        )
        if self.lora_rank:
            config["lora_rank"] = self.lora_rank
            config["lora_alpha"] = self.lora_alpha
        return config

    def _check_load_own_variables(self, store):
        all_vars = self._trainable_variables + self._non_trainable_variables
        if len(store.keys()) != len(all_vars):
            if len(all_vars) == 0 and not self.built:
                raise ValueError(
                    f"Layer '{self.name}' was never built "
                    "and thus it doesn't have any variables. "
                    f"However the weights file lists {len(store.keys())} "
                    "variables for this layer.\n"
                    "In most cases, this error indicates that either:\n\n"
                    "1. The layer is owned by a parent layer that "
                    "implements a `build()` method, but calling the "
                    "parent's `build()` method did NOT create the state of "
                    f"the child layer '{self.name}'. A `build()` method "
                    "must create ALL state for the layer, including "
                    "the state of any children layers.\n\n"
                    "2. You need to implement "
                    "the `def build_from_config(self, config)` method "
                    f"on layer '{self.name}', to specify how to rebuild "
                    "it during loading. "
                    "In this case, you might also want to implement the "
                    "method that generates the build config at saving time, "
                    "`def get_build_config(self)`. "

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. In the parent layer's build(), explicitly create child state, e.g. self.conv.build(input_shape).
  2. Implement get_build_config(self) and build_from_config(self, config) so the layer rebuilds its state on load.
  3. Add a save/load round-trip test comparing layer weights before and after.
  4. If the layer legitimately has no weights, fix the checkpoint or exclude it from saved variables.

Example fix

# before
class Block(layers.Layer):
    def build(self, input_shape):
        self.kernel = self.add_weight(shape=input_shape[-1:], name='kernel')  # child never built

# after
class Block(layers.Layer):
    def build(self, input_shape):
        self.conv.build(input_shape)  # builds child Conv state
    def get_build_config(self):
        return {'input_shape': self._build_shape}
    def build_from_config(self, config):
        self.build(config['input_shape'])
Defensive patterns

Strategy: validation

Validate before calling

# CI round-trip test
m2 = keras.models.load_model(path)
assert [w.shape for w in m.weights] == [w.shape for w in m2.weights]

Type guard

def is_rebuildable(layer) -> bool:
    return layer.built or hasattr(layer, 'build_from_config') or layer.count_params() == 0

Try / catch

try:
    model = keras.models.load_model(path)
except ValueError as e:
    if 'was never built' in str(e):
        # fix parent build()/build_from_config, then retry
        raise

Prevention

When it happens

Trigger: Calling keras.models.load_model() (or layer.load_own_variables(store)) on a model containing a custom layer (e.g. a Conv subclass) owned by a parent layer whose build() does not build the child; or loading a model saved with a build config when the custom layer does not implement build_from_config(self, config) and get_build_config().

Common situations: Custom multi-layer wrappers (e.g. ConvBlock owning Conv2D+BN) where the parent's build creates weights directly instead of building children; loading models across Keras 2->3 migration; custom layers restored from config whose build never runs because build_from_config is absent.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/0d8c266ece30c29d. Report an issue: GitHub.