NVIDIA-NeMo / NVIDIA-NeMo/Guardrails
bug: `ValueError: Unknown role: context` when using `guardrails.context` on a rail config with `passthrough: true`
Nobody has claimed this yet.
- 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
- 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
- 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
- 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
- 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
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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