Configuration Errors
These errors appear when running gym env start or gym eval run --no-serve. NeMo Gym validates configuration at startup before launching servers, and checks the model endpoints the config names once its own servers are up.
See the Configuration reference for complete configuration syntax and options.
Startup Errors
Errors that prevent servers from starting.
Unset Required Config Value(s)
When: One or more required variables (usually in env.yaml) are left unset (???) after all
config sources are merged. Every unset value is listed together in this single error.
Fix: Add the missing value to env.yaml:
Or pass via command line:
Server Reference Not Found
When: A server config references another server that doesn’t exist or isn’t loaded. The error
names the referencing instance/field and then either suggests a similarly named server
(Did you mean: …) or, when nothing is close, lists the available servers of that type
(Available resources_servers: …).
Common causes:
- Typo in the server name
- Referenced server’s config file not included in the
--configflags - Server defined in a different config file that wasn’t loaded
Fix:
- Check server name spelling in your config
- Ensure all required config files are passed with
--config:
Config Path Not Found
When: A config_paths entry (in a config file or a --config flag) points at a file that doesn’t
exist under any search root. The error lists every location that was searched.
Fix: Correct the path. A relative entry is resolved against your working directory and then the Gym install root, so running from the repository root usually fixes it; an absolute path also works.
Malformed config_paths
When: config_paths is set to a scalar or mapping instead of a list of path strings.
Fix: Make it a YAML list, or pass each config with --config:
Malformed head_server Values
When: A head_server field has the wrong type — typically a ++head_server.port= override that is not an
integer, or an explicit host: null — or the whole block was given as something other than a mapping
(++head_server=foo, ++head_server=false, '++head_server=[]'), which reports
'head_server' must be a mapping ... instead. Either key may be omitted (Gym fills the default), as may the whole
block, but a value that is present must be well-typed.
Fix: Give host a hostname or IP and port an integer, in the config or on the command line:
No Server Instances Configured
When: The merged config defines no server instances — usually a wrong/empty --config or a
config_paths list that resolved to nothing.
Fix: Pass the configs that define your servers, or check the config_paths entries actually load.
Catch all of the above before launch with gym env validate — it
merges and validates the same config gym env start uses, then exits with a clean message (no traceback)
and a non-zero status on failure, so it fits in CI pre-flight checks.
Validation Errors
Errors where config structure is correct but values are invalid.
Almost-Servers Detected
When: Config has the right structure (server type, entrypoint) but contains invalid field values.
Common causes:
- Invalid
domainvalue for resources servers - Invalid
licensevalue in dataset configs - Missing required fields for the server type
Fix: Check the validation error path (for example, resources_servers -> example_server -> domain) and update the field with a valid value. Refer to Configuration for valid field values.
Bypass Strict Validation
To continue with invalid configs (invalid servers will be skipped):
Bypassing validation means invalid servers won’t start. Use this only for debugging, not production.
Agent Without an Environment Server
When: An agent instance has no environment server naming it in agent_server.
Rollout collection reaches agents only through an environment server.
Gym therefore generates a legacy_agent relay in front of the agent and logs this warning.
Your config keeps running for now, but a future release will make this an error, so migrate it.
Fix: Declare the environment servers in your config. From a NeMo Gym checkout, run the migration script on your config files or directories:
The script appends a block to each config that needs one and leaves the existing content unchanged, comments included.
It skips agents that an environment server already names.
It also skips agents that only override fields of an agent defined elsewhere.
Run without paths, it updates this repository’s configs.
It exits with 1 under --check when something needs adding, and with 2 when a file cannot be read.
You can also add the block by hand. The warning prints the exact block for each agent; add it at the same level as the agents:
For a top-level _inherit_from rename with one destination that still defines exactly one agent, Gym automatically points environment server references at the new name.
The server keeps its name, so environment_server_routes still resolve.
The migration script leaves these renames alone.
If several destinations inherit the same source and remain agents, and an environment server still references the old name, Gym reports AmbiguousAgentRenameError with the destinations and the field to update.
Give each new agent its own environment server by inheriting the original server and naming that agent, for example:
Apply this pattern to each variant so every agent has a declared environment server, including when error_on_agent_without_environment_server is enabled.
Alternatively, point the existing server’s field at one agent and ensure the other agents also have environment servers.
Do not add a second server in front of an agent, because that makes agent-routed rows ambiguous.
Move a simple_agent Off the Relay
A legacy_agent relay sends the whole episode to the agent’s /run as one request, so a crash repeats the whole episode.
single_agent_turn_legacy runs the same episode in steps (seed, agent turn, agent close, verify), so a crash repeats only the current step, and simple_agent resumes inside its turn.
To replace the relays in front of simple_agent in your configs:
Pass the configs that declare the relays yours inherit as well, such as the Resources Server configs a benchmark includes; run without paths to switch this repository’s configs.
Each relay is replaced by a single_agent_turn_legacy server of the same name. The migration copies the agent’s Resources Server reference into the Environment Server’s resources_server field and grants the agent direct HTTP access to its tools, as the relay’s /run used them. Inherited Environment Servers also receive their own explicit resources binding.
The Environment Server owns this binding at runtime. Both single_agent_turn and single_agent_turn_legacy require resources_server; leaving it unset or setting it to null no longer reads the agent’s configuration. Configs migrated by an earlier version of the script must add the reference to their Environment Server, including child configs that change the resources binding.
Configuration resolution follows a top-level _inherit_from rename when the original Resources Server is removed and exactly one resources instance replaces it. For example, the shared math Environment Server follows math_with_judge to indic_math_500_math_with_judge_resources_server in indic/math_500. If several resources instances inherit the same source, a reference to the removed source is ambiguous and resolution reports the field to update.
A _copy keeps the original resources instance, so its references stay unchanged. Set the child Environment Server’s resources_server explicitly when it should use the copy, as indic/ifeval does. Likewise, changing an agent’s resources setting does not change the Environment Server’s binding. The migration script refuses a switch when an included config changes that pairing without a matching Environment Server override.
A relay stays, and is listed with its reason, when:
- the agent binds no Resources Server, or declares a required MCP tool access or another direct HTTP tool access, which
simple_agentsessions reject; - the agent’s Resources Server has a
seed_sessionthat accepts only the legacy body rather than theResourcesSeedSessionRequestan Environment Server sends, has request models that read the row’s_ng_*rollout coordinates, which an Environment Server does not forward, or has no source underresources_servers/to check; - the relay sets keys the switched server would not keep, such as
port; - another config merges it with a
legacy_agentserver of the same name, such as a benchmark variant that points it at another harness; - the run cannot load one of its included configs.
A relay that inherits another relay keeps its _inherit_from, and the two must switch in the same run; the script exits with 2 and names the relays when only one would switch.
It also exits with 2 when another config merges an inheriting relay with a legacy_agent server while the relay it inherits switches. That config should keep the server’s name, so rows keep their routing, and replace its definition, as benchmarks/hle/opencode_legacy_agent.yaml does: _delete_key: _inherit_from detaches it from the switched relay, _delete_key: single_agent_turn_legacy under its environment_servers removes the migrated type, and a complete legacy_agent server fronts its harness. Set the inherited relay to null when nothing else in the run uses it.
The script writes nothing when it exits with 2.
Compare the reward profile of a switched config with the relay’s before relying on it.
Require Declared Environment Servers
To make a missing environment server an error instead (AgentWithoutEnvironmentServerError):
Environment Server Config Does Not Match Its Server
When: An environment server block names its server type and entrypoint, but its fields don’t match the config class of the server that entrypoint runs.
gym env validate reports this before anything starts.
gym env start reports it only when that server launches, after the other servers are up.
gym env resolve still prints the config and reports the same fields as a warning.
Common causes:
- Switching a block to another server type (for example,
legacy_agenttosingle_agent_turn_legacy) without adding the fields the new type requires - A misspelled field name
Fix: Set or correct each field at the path listed. The server’s configs/ directory under environment_servers/ shows the fields it accepts.
If the server’s entrypoint can’t be loaded in the environment gym runs in, for example because it needs a package installed only in the server’s own virtual environment, gym env validate warns that it could not check that server and leaves the check to its launch.
Connection Errors
Errors where the config is valid but an endpoint it names cannot be reached.
Head Server Unreachable
When: gym eval run --no-serve collects against servers that are already running, and found nothing
listening at the head server address in its config. Either no gym env start is running, or it was started
with a different head server address than this command is using. That address is head_server.host /
head_server.port (default 127.0.0.1:11000). When head_server.host is not set, an explicit
default_host takes precedence. If neither host setting is supplied,
use_absolute_ip selects the machine’s resolved IP
address when true, or 127.0.0.1 when false. A gym env start run with different host settings can
therefore listen on a different address than the collecting command expects.
Fix: Check which head server address gym env start used (from its config and overrides), then run
gym env status with matching overrides before concluding that nothing is running. gym env status only
queries the head server address in its own config, so servers running on another host or port also show
No NeMo Gym servers found running.
If status lists your servers, pass the same overrides to the collecting command:
If status finds no servers at the matching address either, start them with gym env start (in another
terminal or the background) and retry.
Gym Server Startup Timeout
Gym stops waiting when its managed servers have not become ready within server_spinup_timeout_seconds (default 600). The error names the server instances still waiting. This bound also catches a multi-worker Uvicorn manager that remains alive while repeatedly replacing workers that fail during application construction.
The budget starts when Gym begins polling its servers for readiness, which happens after it has launched them and its head server is answering. Head-server startup does not count against it. The budget covers whatever each server still has to do before it opens its port. That includes installing the server’s dependencies and, for a locally launched model such as local_vllm_model, downloading and loading the model weights: that server waits for its inference engine before the Gym port opens. model_endpoint_readiness_timeout_seconds is a separate, later check of the model endpoints named in the config, so raising it does not help at this stage.
Raise the value for servers with legitimately long initialization with ++server_spinup_timeout_seconds=<seconds>, or set it to 0 to preserve an unbounded wait while debugging. The value must be a number of seconds; anything else is reported as a configuration error before any server starts. A deterministic startup exception should be fixed rather than hidden behind a larger timeout.
Server Shutdown
Managed servers run in separate process sessions. On shutdown, Gym sends each server group one SIGINT and waits within one shared server_shutdown_timeout_seconds grace period (default 1). Set it to finite nonnegative seconds; numeric strings are accepted, and 0 requests immediate escalation. Invalid values fail before any server starts. After the grace expires, Gym sends SIGKILL to the remaining groups and uses one additional bounded reap interval. Descendants remain part of the owned group even if the launching shell exits first. The HTTP sidecar stays alive until the servers stop, with its own shutdown grace; telemetry and head-server teardown also fall outside the managed-server grace.
Agent servers use their lifespan shutdown to close remaining sessions concurrently. One session_close_timeout_seconds budget bounds the whole drain, including incomplete setup and cleanup already in progress. This field still bounds individual close phases during normal operation. Its base default is 60 seconds; adapters may keep their own defaults, including 30 for Hermes and Stirrup. A timeout cancels pending cleanup and reports unconfirmed session IDs. Unconfirmed cleanup retains its handle and leaves no saved reply; process exit does not establish that a remote sandbox stopped, so its owner and provider TTL remain responsible after forced termination.
Allow the managed-server grace to exceed the longest agent drain plus Uvicorn request cancellation and process overhead. The default one-second grace does not guarantee a sixty-second agent drain. For example, if request cancellation and shutdown overhead fit within ten seconds:
An external supervisor’s shutdown deadline must exceed these budgets too, or it can kill Gym before graceful cleanup completes.
Model Endpoint Unreachable
When: gym env start finished starting Gym’s own servers, but a model endpoint named in the config is not answering. Gym’s model server is a proxy that answers as soon as it starts, whether or not an inference server is behind it, so this check is separate from the server readiness check above it.
Fix: Check the config key named beside each URL, and confirm something answers there. The check probes /models under a base URL ending in /v1, and the URL itself otherwise, and connects directly rather than through a proxy, so mirror whichever applies:
Any response other than 502, 503 or 504, including 401 or 404, means something is listening. A 502, 503 or 504 usually comes from a proxy or load balancer whose backend is still starting. Then correct that config key, or start the server it names. The Quickstart uses a hosted endpoint (https://api.openai.com/v1); a localhost URL means you serve the model yourself (see Configure Model).
The check waits up to model_endpoint_readiness_timeout_seconds (default 600) so an inference server still loading weights is not treated as a failure. Raise it to wait longer, or set it to 0 to skip the check entirely.
An endpoint whose hostname does not resolve is reported once and not waited on, since waiting cannot create a DNS record. This is what happens to a config that leaves a judge or user model at its placeholder default: you get one line about it rather than a stalled startup.
Any HTTP answer counts as listening, including 401 and 404, except 502, 503 and 504: a proxy or load balancer in front of an inference server returns those while the server behind it is still loading, so the check keeps waiting. A completed TLS handshake counts too, even against a certificate this machine does not trust, because it proves something is there.
The check ignores HTTP_PROXY, HTTPS_PROXY and ALL_PROXY and connects directly, as Gym’s model requests do.