mudler/LocalAI · error · ValueError

Inline reward function '{name}' must return a list, got {typ

Error message

Inline reward function '{name}' must return a list, got {type(result).__name__}

What it means

After exec'ing an inline reward, the backend smoke-tests it with func(["test"], answer=["test"]) and requires the return value to be a list (TRL's reward contract: one float per completion). Returning a scalar, numpy array, tuple, or None triggers this ValueError naming the actual type; note the 'must return a list' check re-raises even inside the broad except.

Source

Thrown at backend/python/trl/reward_functions.py:180

        "re": re,
        "math": math,
        "json": json,
        "string": string,
    }

    try:
        compiled = compile(func_source, f"<inline-reward-{name}>", "exec")
    except SyntaxError as e:
        raise ValueError(f"Syntax error in inline reward function '{name}': {e}")

    exec(compiled, restricted_globals)
    func = restricted_globals[f"_user_reward_{name}"]

    # Validate with a quick smoke test
    try:
        result = func(["test"], answer=["test"])
        if not isinstance(result, list):
            raise ValueError(
                f"Inline reward function '{name}' must return a list, got {type(result).__name__}"
            )
    except Exception as e:
        if "must return a list" in str(e):
            raise
        # Other errors during smoke test are acceptable (e.g. missing kwargs)
        pass

    return func


# ---------------------------------------------------------------------------
# Dispatcher
# ---------------------------------------------------------------------------

def build_reward_functions(specs_json):
    """Parse a JSON list of reward function specs and return a list of callables.

View on GitHub (pinned to 44413a9d06)

Solutions

  1. Return a list with one value per completion: return [score for c in completions].
  2. If using numpy, convert: return scores.tolist().
  3. Keep the length equal to len(completions); wrap accidental scalars as [value] only when there is exactly one completion.

Example fix

# before
def _user_reward_acc(c, **kw):
    return 1.0 if c[0] == kw["answer"][0] else 0.0
# after
def _user_reward_acc(c, **kw):
    return [1.0 if x == a else 0.0 for x, a in zip(c, kw["answer"])]
Defensive patterns

Strategy: validation

Validate before calling

def reward_returns_list(func, sample=("test",)) -> bool:
    try:
        out = func(list(sample), answer=list(sample))
    except Exception:
        return True  # smoke errors are tolerated by the backend
    return isinstance(out, list)

Type guard

from typing import Any, Callable

def is_list_returning_reward(f: Callable) -> bool:
    out = f(["test"], answer=["test"])
    return isinstance(out, list)

Try / catch

try:
    funcs = build_reward_functions(specs)
except ValueError as e:
    if "must return a list" in str(e):
        raise ConfigError("reward must return one float per completion") from e
    raise

Prevention

When it happens

Trigger: Inline code returning sum(scores) instead of scores; returning a numpy array (isinstance(np.array, list) is False); early return None on an edge case; generator expression returned unmaterialized.

Common situations: Users porting reward code from single-sample scripts that returned one float; forgetting TRL batches completions.

Related errors


AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15). Data as JSON: /api/errors/76a71ac81fd5e097. Report an issue: GitHub.