Skip to content

[Docs] safe_mode=True does not isolate built-in class names from get_custom_objects() registry #22466

@amadhan882

Description

@amadhan882

Description

The documentation for safe_mode in deserialize_keras_object only states it protects against "unsafe lambda deserialization."

However, the parameter name safe_mode implies broader safety guarantees. Users are not warned that safe_mode=True does NOT isolate built-in class name resolution from the custom object registry. This creates a documentation gap that could mislead developers into assuming stronger protections than exist.

Poc

import keras
from keras.src.saving import serialization_lib

class CustomDense(keras.layers.Layer):
    def __init__(self, **kwargs):
        super().__init__()
        print("CustomDense called instead of real Dense")
    def call(self, x):
        return x

keras.utils.get_custom_objects()["Dense"] = CustomDense

config = {
    "class_name": "Dense",
    "config": {"units": 5, "name": "test"},
    "registered_name": "Dense"
}


serialization_lib.deserialize_keras_object(config, safe_mode=True)

Observed Result


CustomDense called instead of real Dense
<CustomDense name=custom_dense, built=False>

Expected Behavior

safe_mode=True should resolve "Dense" to the built-in keras.layers.Dense, ignoring any custom registry overrides for built-in class names.

Actual Behavior

safe_mode=True silently resolves "Dense" to the custom registry entry, bypassing the built-in class entirely.

Suggested improvement

safe_mode parameter documentation to explicitly state that it only protects against Lambda layer deserialization and does not isolate built-in class names from overrides via keras.utils.get_custom_objects().

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions