BerriAI/litellm · error · SyntaxError

augmented assignment {op!r} is not supported

Error message

augmented assignment {op!r} is not supported

What it means

SyntaxError raised by the sandbox's _inplacevar_ helper when RestrictedPython rewrites an augmented assignment (x += 1) into _inplacevar_('+=', x, 1) and the operator string is not in the supported table. The shipped _INPLACE_OPS table maps all 13 Python augmented operators, so in practice this branch is defensive: reaching it means the installed RestrictedPython emitted an operator token this litellm sandbox version does not map (dependency drift), not that '+=' itself is banned.

Source

Thrown at litellm/proxy/guardrails/guardrail_hooks/custom_code/sandbox.py:85

    "%=": operator.imod,
    "**=": operator.ipow,
    "@=": operator.imatmul,
    "&=": operator.iand,
    "|=": operator.ior,
    "^=": operator.ixor,
    "<<=": operator.ilshift,
    ">>=": operator.irshift,
}


def _inplacevar_(op: str, x: Any, y: Any) -> Any:
    # RestrictedPython rewrites ``x += 1`` on a simple name into
    # ``x = _inplacevar_("+=", x, 1)``. The package deliberately ships no
    # default, so we dispatch through ``operator``'s in-place helpers, which
    # honour Python's normal ``__iadd__``/``__add__`` fallback.
    fn: Final = _INPLACE_OPS.get(op)
    if fn is None:
        raise SyntaxError(f"augmented assignment {op!r} is not supported")
    return fn(x, y)


def _build_sandbox_builtins() -> dict[str, Any]:
    # ``limited_builtins`` overrides ``list``/``tuple``/``range`` from
    # ``safe_builtins`` with bounds-checking variants (e.g. ``limited_range``
    # rejects ``range(10**18)``). ``utility_builtins`` adds ``set``,
    # ``frozenset``, ``math``, ``random``, and a filtered ``string`` delegator.
    return {
        **safe_builtins,
        **limited_builtins,
        **utility_builtins,
    }


def build_sandbox_globals() -> dict[str, Any]:
    """Assemble the globals dict for executing guardrail code.

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Pin RestrictedPython to the version the installed litellm was tested with
  2. As a workaround, rewrite the augmented assignment as explicit rebinding: x = x + y
  3. Upgrade or downgrade litellm so sandbox.py matches the installed RestrictedPython
  4. Report the op string shown in the message — it identifies the unmapped operator

Example fix

# before (custom_code, hits an unmapped op after dependency drift)
score @= weights

# after: explicit rebinding
score = score @ weights
Defensive patterns

Strategy: validation

Validate before calling

import RestrictedPython, litellm
from litellm.proxy.guardrails.guardrail_hooks.custom_code.sandbox import (
    build_sandbox_globals, compile_sandboxed,
)

def sandbox_compile_check(src: str) -> None:
    g = build_sandbox_globals()          # uses the same _inplacevar_ table
    exec(compile_sandboxed(src), g)      # any unmapped augmented op raises here

print('RestrictedPython', RestrictedPython.__version__, '| litellm', litellm.__version__)

Try / catch

from litellm.proxy.guardrails.guardrail_hooks.custom_code.custom_code_guardrail import CustomCodeCompilationError
try:
    guardrail._compile_custom_code()
except CustomCodeCompilationError as e:
    if 'augmented assignment' in str(e):
        # dependency drift: rewrite to explicit rebinding or pin RestrictedPython
        log.error('sandbox/litellm version mismatch: %s', e)
    raise

Prevention

When it happens

Trigger: Custom code uses an augmented assignment whose rewritten op string misses the table — only plausible with a mismatched/newer RestrictedPython emitting an unexpected token; standard +=, -=, @=, <<= etc. all work. Surfacing at compile/exec time it wraps into 'Syntax error in custom code', and inside a running function it surfaces as CustomCodeExecutionError.

Common situations: RestrictedPython upgraded independently of litellm (pip resolver drift); base image rebuilt with newer transitive dependencies; error message quotes an operator the sandbox does not recognize.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/84544cc0ef83dfa2. Report an issue: GitHub.