{"record":{"id":"9f55212b2fe60811","repo":"mudler/LocalAI","slug":"reward-funcs-must-be-a-json-array-of-reward-functi","errorCode":null,"errorMessage":"reward_funcs must be a JSON array of reward function specs","messagePattern":"reward_funcs must be a JSON array of reward function specs","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/python/trl/reward_functions.py","lineNumber":211,"sourceCode":"# Dispatcher\n# ---------------------------------------------------------------------------\n\ndef build_reward_functions(specs_json):\n    \"\"\"Parse a JSON list of reward function specs and return a list of callables.\n\n    Each spec is a dict with:\n      - type: \"builtin\" or \"inline\"\n      - name: function name\n      - code: (inline only) Python function body\n      - params: (optional) dict of string params applied via functools.partial\n    \"\"\"\n    if isinstance(specs_json, str):\n        specs = json.loads(specs_json)\n    else:\n        specs = specs_json\n\n    if not isinstance(specs, list):\n        raise ValueError(\"reward_funcs must be a JSON array of reward function specs\")\n\n    reward_funcs = []\n    for spec in specs:\n        spec_type = spec.get(\"type\", \"builtin\")\n        name = spec.get(\"name\", \"\")\n        params = spec.get(\"params\", {})\n\n        if spec_type == \"builtin\":\n            if name not in BUILTIN_REGISTRY:\n                available = \", \".join(sorted(BUILTIN_REGISTRY.keys()))\n                raise ValueError(\n                    f\"Unknown builtin reward function '{name}'. Available: {available}\"\n                )\n            func = BUILTIN_REGISTRY[name]\n            if params:\n                # Convert string params to appropriate types\n                typed_params = {}\n                for k, v in params.items():","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/backend/python/trl/reward_functions.py#L193-L229","documentation":"build_reward_functions accepts the reward spec either as a pre-parsed list or as a JSON string; after json.loads (or direct use), the top level must be a JSON array. Passing a single object, a dict, or a double-encoded JSON string ('\\\"[...]\\\"' which loads to a str) fails this isinstance check.","triggerScenarios":"extra_options['reward_funcs'] = '{\\\"type\\\": ...}' (single object, not array); reward_funcs='\\\"[ {...} ]\\\"' (JSON string of a JSON string); passing a bare function name string like 'format_reward'.","commonSituations":"Building the extra_options dict in code and forgetting json.dumps of the list; hand-writing JSON in YAML model configs; clients that stringify twice.","solutions":["Wrap the spec in a list: '[{\"type\":\"builtin\",\"name\":\"format_reward\"}]'.","If constructing programmatically, pass the Python list directly (build_reward_functions accepts both) instead of ad-hoc string building.","Validate with json.loads(spec) in a unit test and assert isinstance(result, list)."],"exampleFix":"# before\nextra[\"reward_funcs\"] = json.dumps({\"type\": \"builtin\", \"name\": \"format_reward\"})\n# after\nextra[\"reward_funcs\"] = json.dumps([{ \"type\": \"builtin\", \"name\": \"format_reward\" }])","handlingStrategy":"validation","validationCode":"import json\n\ndef reward_specs_valid(specs) -> bool:\n    parsed = json.loads(specs) if isinstance(specs, str) else specs\n    return isinstance(parsed, list)","typeGuard":"def is_reward_spec_list(x) -> bool:\n    import json\n    p = json.loads(x) if isinstance(x, str) else x\n    return isinstance(p, list) and all(isinstance(s, dict) for s in p)","tryCatchPattern":"try:\n    build_reward_functions(extra[\"reward_funcs\"])\nexcept ValueError as e:\n    if \"JSON array\" in str(e):\n        extra[\"reward_funcs\"] = json.dumps([json.loads(extra[\"reward_funcs\"])])\n        retry\n    raise","preventionTips":["Always pass the Python list (or json.dumps(list)) — never dicts or double-encoded strings.","Schema-validate extra_options in client SDKs.","Add a JSON schema for reward specs to your API docs."],"tags":["trl","reward-functions","json","validation","localai"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}