{"record":{"id":"27107590c27a3cb4","repo":"BerriAI/litellm","slug":"margin-percentage-for-provider-must-be-a-number","errorCode":null,"errorMessage":"Margin percentage for {provider} must be a number","messagePattern":"Margin percentage for (.+?) must be a number","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"litellm/proxy/management_endpoints/cost_tracking_settings.py","lineNumber":378,"sourceCode":"                \"error\": f\"Invalid provider(s): {', '.join(invalid_providers)}. Must be valid LiteLLM providers or 'global'. See https://docs.litellm.ai/docs/providers for the full list.\"\n            },\n        )\n\n    # Validate margin values\n    for provider, margin_value in cost_margin_config.items():\n        if isinstance(margin_value, (int, float)):\n            # Simple percentage format: {\"openai\": 0.10}\n            if not (0 <= margin_value <= 10):  # Allow up to 1000% margin\n                raise HTTPException(\n                    status_code=400,\n                    detail=f\"Margin percentage for {provider} must be between 0 and 10 (0% to 1000%)\",\n                )\n        elif isinstance(margin_value, dict):\n            # Complex format: {\"percentage\": 0.08, \"fixed_amount\": 0.0005}\n            if \"percentage\" in margin_value:\n                percentage = margin_value[\"percentage\"]\n                if not isinstance(percentage, (int, float)):\n                    raise HTTPException(\n                        status_code=400,\n                        detail=f\"Margin percentage for {provider} must be a number\",\n                    )\n                if not (0 <= percentage <= 10):\n                    raise HTTPException(\n                        status_code=400,\n                        detail=f\"Margin percentage for {provider} must be between 0 and 10 (0% to 1000%)\",\n                    )\n            if \"fixed_amount\" in margin_value:\n                fixed_amount = margin_value[\"fixed_amount\"]\n                if not isinstance(fixed_amount, (int, float)):\n                    raise HTTPException(\n                        status_code=400,\n                        detail=f\"Fixed margin amount for {provider} must be a number\",\n                    )\n                if fixed_amount < 0:\n                    raise HTTPException(\n                        status_code=400,","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/cost_tracking_settings.py#L360-L396","documentation":"Validation error (HTTP 400) from PATCH /config/cost_margin_config when using the complex dict format ({\"percentage\": ..., \"fixed_amount\": ...}) and the 'percentage' field is present but not an int/float (e.g. the string \"0.08\" or null).","triggerScenarios":"Sending {\"openai\": {\"percentage\": \"0.08\", \"fixed_amount\": 0.001}} — the percentage arrived stringified from env vars, templates, or YAML string coercion.","commonSituations":"Config generators that stringify all scalars; hand-written JSON with quotes around numbers; copy-paste from documentation examples where quotes slipped in.","solutions":["Make 'percentage' a bare JSON number: {\"percentage\": 0.08}.","Cast values with float() when building the payload programmatically.","Omit 'percentage' entirely if you only want fixed_amount."],"exampleFix":"# before\n{\"openai\": {\"percentage\": \"0.08\"}}\n\n# after\n{\"openai\": {\"percentage\": 0.08}}","handlingStrategy":"type-guard","validationCode":"for provider, margin in cost_margin_config.items():\n    if isinstance(margin, dict) and \"percentage\" in margin:\n        p = margin[\"percentage\"]\n        if isinstance(p, str):\n            margin[\"percentage\"] = p = float(p)  # coerce or fail\n        assert isinstance(p, (int, float)) and not isinstance(p, bool), f\"{provider}.percentage must be numeric\"","typeGuard":"def is_valid_margin_dict(m: dict) -> bool:\n    ok = True\n    if \"percentage\" in m:\n        ok &= isinstance(m[\"percentage\"], (int, float)) and not isinstance(m[\"percentage\"], bool)\n    if \"fixed_amount\" in m:\n        ok &= isinstance(m[\"fixed_amount\"], (int, float)) and not isinstance(m[\"fixed_amount\"], bool)\n    return ok and bool(m)","tryCatchPattern":null,"preventionTips":["Keep 'percentage' and 'fixed_amount' as bare JSON numbers.","Run a payload schema check (e.g. jsonschema) before PATCHing."],"tags":["litellm-proxy","validation","type-error","cost-tracking"],"backgroundTag":"type-validation-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}