NVIDIA-NeMo / NVIDIA-NeMo/Guardrails

bug: `ValueError: Unknown role: context` when using `guardrails.context` on a rail config with `passthrough: true`

Open
#2,233 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug status: needs triage
Dominant language
Python
Stars
7.2k
Forks
842
Avg merge
3d 1h
Merged PRs (30d)
25

Description

Did you check docs and existing issues?
  • I have read all the NeMo-Guardrails docs
  • I have updated the package to the latest version before submitting this issue
  • (optional) I have used the develop branch
  • I have searched the existing issues of NeMo-Guardrails
Python version (python --version)

Python 3.12.3

Operating system/version

Ubuntu 24.04.3 LTS

NeMo-Guardrails version (if you must use a specific version and not the latest

0.23.0

Describe the bug

Sending a chat completion request with guardrails.context set and a config that has passthrough: true results in a ValueError: Unknown role: context. The request fails with an internal error response instead of reaching the LLM.

I have to use passthrough: true in my config to support agents that use tool calls (tools / tool_choice parameters), as the server returns 422 without it.

Steps To Reproduce
  1. Config a rail in ./config/my-config/config.yml
models:
  - type: main
    engine: openai
    model: openai/my-model
    parameters:
      base_url: https://my-llm-endpoint/v1
      api_key: EMPTY

passthrough: true

rails:
  input:
    flows:
      - check user info
  1. Define the flow that passes when the user is not blocked: (./config/my-config/rails.co)
define bot inform blocked
  "I'm sorry, you are blocked."

define subflow check user info
  $allowed = execute check_user
  if not $allowed
    bot inform blocked
    stop
  1. Define the check_user action (./config/my-config/actions.py)
from nemoguardrails.actions import action

@action(name="check_user", is_system_action=True)
async def check_user(context: dict = None) -> bool:
    if context:
        user = context.get("user_id")
        return user != "block-me" # block this user, allow anyone else

    return True  # allow
  1. Start the Guardrails server
# omitted for simplicity - export ENV variables for SSL_CERT_DIR, MAIN_MODEL_ENGINE="vllm", MAIN_MODEL_BASE_URL...
nemoguardrails server --config ./config --port 8000 --auto-reload --verbose
  1. Send the request via CURL

Set user_id in context: for example "alice" (allowed) or "block-me" (blocked)

curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/my-model",
    "messages": [
      {"role": "user", "content": "Hello"}
    ],
    "guardrails": {
      "config_id": "my-config",
      "context": {"user_id": "alice"}
    }
  }'
Expected Behavior

When the input rail allows the request through (user_id: "alice"), it should be forwarded to the LLM and the response returned to the caller. Having the "role": "context" in the messages list should not affect the LLM call.

Actual Behavior

The server returns:

{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": "I'm sorry, an internal error has occurred."
    }
  }]
}

Server log:

ERROR:nemoguardrails.actions.action_dispatcher:Unknown role: context
Traceback (most recent call last):
  File ".../nemoguardrails/actions/action_dispatcher.py", line 215, in execute_action
    result = await result
  File ".../nemoguardrails/actions/llm/generation.py", line 510, in generate_user_intent
    await llm_call(
  File ".../nemoguardrails/actions/llm/utils.py", line 75, in llm_call
    chat_prompt = _ensure_chat_messages(prompt)
  File ".../nemoguardrails/actions/llm/utils.py", line 47, in _ensure_chat_messages
    return [ChatMessage.from_dict(d) for d in prompt]
  File ".../nemoguardrails/types.py", line 165, in from_dict
    raise ValueError(f"Unknown role: {raw_role}")
ValueError: Unknown role: context

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with nemoguardrails/types.py and the _ensure_chat_messages path in nemoguardrails/actions/llm/utils.py, then trace the call from generation.py shown in the traceback. Reproduce the request with the provided rail configuration and CURL command; done means the context-bearing request reaches the LLM without the Unknown role: context error and returns the expected response.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.