{"record":{"id":"05488166eedf8236","repo":"keras-team/keras","slug":"requested-the-deserialization-of-a-tfsmlayer-wh","errorCode":null,"errorMessage":"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().","messagePattern":"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\\(\\)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/export/tfsm_layer.py","lineNumber":172,"sourceCode":"        Args:\n            config: A Python dictionary, typically the output of `get_config`.\n            custom_objects: Optional dictionary mapping names to custom objects.\n            safe_mode: Boolean, whether to disallow loading TFSMLayer.\n                When `safe_mode=True`, loading is disallowed because TFSMLayer\n                loads external SavedModels that may contain attacker-controlled\n                executable graph code. Defaults to `True`.\n        Returns:\n            A TFSMLayer instance.\n        \"\"\"\n        # Follow the same pattern as Lambda layer for safe_mode handling\n        effective_safe_mode = (\n            safe_mode\n            if safe_mode is not None\n            else serialization_lib.in_safe_mode()\n        )\n\n        if effective_safe_mode is not False:\n            raise ValueError(\n                \"Requested the deserialization of a `TFSMLayer`, which \"\n                \"loads an external SavedModel. This carries a potential risk \"\n                \"of arbitrary code execution and thus it is disallowed by \"\n                \"default. If you trust the source of the artifact, you can \"\n                \"override this error by passing `safe_mode=False` to the \"\n                \"loading function, or calling \"\n                \"`keras.config.enable_unsafe_deserialization().\"\n            )\n\n        return cls(**config)\n","sourceCodeStart":154,"sourceCodeEnd":183,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/export/tfsm_layer.py#L154-L183","documentation":"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.","triggerScenarios":"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.","commonSituations":"Serializing a wrapper model that contains a TFSMLayer; CI tests that deserialize layers; loading third-party .keras artifacts from untrusted sources.","solutions":["If you trust the artifact source, opt in once: keras.config.enable_unsafe_deserialization() before deserializing.","Or pass safe_mode=False to the specific loading function (keras.saving.load_model(..., safe_mode=False)).","For untrusted artifacts do not bypass; inspect the SavedModel (tf.saved_model.load) in a sandbox instead."],"exampleFix":"# before\ncfg = layer.get_config()\nnew_layer = keras.layers.deserialize(cfg)  # -> ValueError\n\n# after\nimport keras\nkeras.config.enable_unsafe_deserialization()\nnew_layer = keras.layers.deserialize(cfg)","handlingStrategy":"try-catch","validationCode":"import keras\n\ndef can_deserialize_unsafe():\n    return getattr(keras.config, 'is_unsafe_deserialization_enabled', lambda: False)()","typeGuard":null,"tryCatchPattern":"try:\n    layer = keras.layers.deserialize(cfg)\nexcept ValueError as e:\n    if 'unsafe_deserialization' in str(e) and trusted_source:\n        keras.config.enable_unsafe_deserialization()\n        layer = keras.layers.deserialize(cfg)\n    else:\n        raise","preventionTips":["Enable unsafe deserialization only in trusted local jobs; keep it off in services that accept uploads.","Prefer exporting to .keras checkpoints that do not wrap external SavedModels.","Never auto-bypass the guard for untrusted artifacts."],"tags":["keras","tfsmlayer","deserialization","security","unsafe-deserialization"],"backgroundTag":"unsafe-deserialization-blocked","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}