{"record":{"id":"e31deb48783103c9","repo":"PaddlePaddle/PaddleOCR","slug":"the-type-of-eta-min-in-cosineannealingdecay-mu","errorCode":null,"errorMessage":"The type of 'eta_min' in 'CosineAnnealingDecay' must be 'float, int', but received %s.","messagePattern":"The type of 'eta_min' in 'CosineAnnealingDecay' must be 'float, int', but received (.+?)\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ppocr/optimizer/lr_scheduler.py","lineNumber":183,"sourceCode":"        return computed_lr\n\n\nclass TwoStepCosineDecay(LRScheduler):\n    def __init__(\n        self, learning_rate, T_max1, T_max2, eta_min=0, last_epoch=-1, verbose=False\n    ):\n        if not isinstance(T_max1, int):\n            raise TypeError(\n                \"The type of 'T_max1' in 'CosineAnnealingDecay' must be 'int', but received %s.\"\n                % type(T_max1)\n            )\n        if not isinstance(T_max2, int):\n            raise TypeError(\n                \"The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received %s.\"\n                % type(T_max2)\n            )\n        if not isinstance(eta_min, (float, int)):\n            raise TypeError(\n                \"The type of 'eta_min' in 'CosineAnnealingDecay' must be 'float, int', but received %s.\"\n                % type(eta_min)\n            )\n        assert T_max1 > 0 and isinstance(\n            T_max1, int\n        ), \" 'T_max1' must be a positive integer.\"\n        assert T_max2 > 0 and isinstance(\n            T_max2, int\n        ), \" 'T_max1' must be a positive integer.\"\n        self.T_max1 = T_max1\n        self.T_max2 = T_max2\n        self.eta_min = float(eta_min)\n        super(TwoStepCosineDecay, self).__init__(learning_rate, last_epoch, verbose)\n\n    def get_lr(self):\n        if self.last_epoch <= self.T_max1:\n            if self.last_epoch == 0:\n                return self.base_lr","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/optimizer/lr_scheduler.py#L165-L201","documentation":"TypeError from TwoStepCosineDecay.__init__ when eta_min is neither float nor int. Unlike T_max1/T_max2, this check accepts both numeric types, so it only fires for genuinely non-numeric input such as strings or None.","triggerScenarios":"Passing eta_min as a quoted string from config (\"0.0\"), None when the config key is absent and defaulted incorrectly, or a numpy array/object.","commonSituations":"YAML configs with quoted numerics; configs templated from JSON where all values became strings; passing optimizer groups or dicts instead of scalars.","solutions":["Provide eta_min as a number: eta_min=1e-5 or eta_min: 0.0 in YAML (unquoted).","If the value may arrive as a string, coerce first: float(eta_min).","If the key is optional in your pipeline, default it explicitly to 0 rather than None."],"exampleFix":"# before\nTwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=30, eta_min=\"0.0\")  # string\n\n# after\nTwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=30, eta_min=0.0)","handlingStrategy":"type-guard","validationCode":"eta_min = float(eta_min if eta_min is not None else 0)","typeGuard":"def is_numeric_eta_min(v) -> bool:\n    return isinstance(v, (int, float)) and not isinstance(v, bool)","tryCatchPattern":null,"preventionTips":["Default absent optional scalars to 0, never None.","Unquote numeric values in YAML/JSON configs."],"tags":["lr-scheduler","type-validation","config","training"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}