keras-team/keras · error · ValueError

Requested the deserialization of a `TFSMLayer`, which loads

Error message

Requested the deserialization of a `TFSMLayer`, which loads an external SavedModel. This carries a potential risk of arbitrary code execution and thus it is disallowed by default. If you trust the source of the artifact, you can override this error by passing `safe_mode=False` to the loading function, or calling `keras.config.enable_unsafe_deserialization().

What it means

Deserializing a TFSMLayer (TFSMLayer.from_config, reached via keras.layers.deserialize or model loading) reloads an external SavedModel, which can execute arbitrary code. Keras therefore refuses by default: if safe_mode is not explicitly False, and global keras.config.enable_unsafe_deserialization() was not called, from_config raises this ValueError. It is a deliberate supply-chain guard, not a bug.

Source

Thrown at keras/src/export/tfsm_layer.py:172

        Args:
            config: A Python dictionary, typically the output of `get_config`.
            custom_objects: Optional dictionary mapping names to custom objects.
            safe_mode: Boolean, whether to disallow loading TFSMLayer.
                When `safe_mode=True`, loading is disallowed because TFSMLayer
                loads external SavedModels that may contain attacker-controlled
                executable graph code. Defaults to `True`.
        Returns:
            A TFSMLayer instance.
        """
        # Follow the same pattern as Lambda layer for safe_mode handling
        effective_safe_mode = (
            safe_mode
            if safe_mode is not None
            else serialization_lib.in_safe_mode()
        )

        if effective_safe_mode is not False:
            raise ValueError(
                "Requested the deserialization of a `TFSMLayer`, which "
                "loads an external SavedModel. This carries a potential risk "
                "of arbitrary code execution and thus it is disallowed by "
                "default. If you trust the source of the artifact, you can "
                "override this error by passing `safe_mode=False` to the "
                "loading function, or calling "
                "`keras.config.enable_unsafe_deserialization()."
            )

        return cls(**config)

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. If you trust the artifact source, opt in once: keras.config.enable_unsafe_deserialization() before deserializing.
  2. Or pass safe_mode=False to the specific loading function (keras.saving.load_model(..., safe_mode=False)).
  3. For untrusted artifacts do not bypass; inspect the SavedModel (tf.saved_model.load) in a sandbox instead.

Example fix

# before
cfg = layer.get_config()
new_layer = keras.layers.deserialize(cfg)  # -> ValueError

# after
import keras
keras.config.enable_unsafe_deserialization()
new_layer = keras.layers.deserialize(cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

import keras

def can_deserialize_unsafe():
    return getattr(keras.config, 'is_unsafe_deserialization_enabled', lambda: False)()

Try / catch

try:
    layer = keras.layers.deserialize(cfg)
except ValueError as e:
    if 'unsafe_deserialization' in str(e) and trusted_source:
        keras.config.enable_unsafe_deserialization()
        layer = keras.layers.deserialize(cfg)
    else:
        raise

Prevention

When it happens

Trigger: Round-tripping a TFSMLayer: layer.get_config() then keras.layers.deserialize(config) (e.g. in test_serialization); keras.models.load_model on a .keras file that embeds a TFSMLayer; loading third-party artifacts that wrap external SavedModels.

Common situations: Serializing a wrapper model that contains a TFSMLayer; CI tests that deserialize layers; loading third-party .keras artifacts from untrusted sources.

Related errors


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