{"record":{"id":"365ece318284f001","repo":"PaddlePaddle/PaddleOCR","slug":"the-norm-layer-must-be-str-or-paddle-nn-layer-laye-365ece","errorCode":null,"errorMessage":"The norm_layer must be str or paddle.nn.layer.Layer class","messagePattern":"The norm_layer must be str or paddle\\.nn\\.layer\\.Layer class","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ppocr/modeling/heads/rec_cppd_head.py","lineNumber":193,"sourceCode":"        else:\n            raise TypeError(\"The norm_layer must be str or paddle.nn.LayerNorm class\")\n        self.mixer = Attention(\n            dim,\n            num_heads=num_heads,\n            qkv_bias=qkv_bias,\n            qk_scale=qk_scale,\n            attn_drop=attn_drop,\n            proj_drop=drop,\n        )\n\n        # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here\n        self.drop_path = DropPath(drop_path) if drop_path > 0.0 else Identity()\n        if isinstance(norm_layer, str):\n            self.norm2 = eval(norm_layer)(dim, epsilon=epsilon)\n        elif isinstance(norm_layer, Callable):\n            self.norm2 = norm_layer(dim)\n        else:\n            raise TypeError(\"The norm_layer must be str or paddle.nn.layer.Layer class\")\n        mlp_hidden_dim = int(dim * mlp_ratio)\n        self.mlp_ratio = mlp_ratio\n        self.mlp = Mlp(\n            in_features=dim,\n            hidden_features=mlp_hidden_dim,\n            act_layer=act_layer,\n            drop=drop,\n        )\n\n    def forward(self, q, kv):\n        x1 = self.norm1(q + self.drop_path(self.mixer(q, kv)))\n        x = self.norm2(x1 + self.drop_path(self.mlp(x1)))\n        return x\n\n\nclass CPPDHead(nn.Layer):\n    def __init__(\n        self,","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_cppd_head.py#L175-L211","documentation":"Second norm guard in the same CPPD Block.__init__, building self.norm2 (norm before the MLP): same contract — norm_layer must be str or Callable, else TypeError('The norm_layer must be str or paddle.nn.layer.Layer class'). Because it re-checks the identical argument after the norm1/normkv guard already passed, this specific line is effectively unreachable in the shipped code; it would only fire in a fork where norm1 and norm2 receive different values.","triggerScenarios":"Not reachable via the public constructor since the identical value already passed the first isinstance chain two statements earlier; would trigger only if a modified version supplies a separate, invalid norm argument for the MLP branch.","commonSituations":"Local forks adding independent pre-attention/pre-MLP norm configuration and passing an instance or None only for the second one.","solutions":["Same as the norm1 guard: pass norm_layer as a class or string","In modified code, validate any second norm argument with the same isinstance(str/Callable) check before use"],"exampleFix":"// not applicable (duplicate guard; fix norm_layer as in the norm1 error)\nnull","handlingStrategy":"type-guard","validationCode":"assert isinstance(norm_layer, (str, Callable)), 'norm_layer must be a str or Callable class'","typeGuard":"from collections.abc import Callable\n\ndef is_valid_norm_layer(n) -> bool:\n    return isinstance(n, (str, Callable)) and not isinstance(n, nn.Layer)","tryCatchPattern":null,"preventionTips":["Same rule as the norm1/normkv guard; this duplicate check is effectively unreachable","Validate once at the top of custom construction code rather than relying on the second raise"],"tags":["api-usage","cppd","defensive-check","type-error"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}