Skip to content

fix(cli): fail fast when gym eval run --split has no matching dataset - #2911

Merged
adil-a merged 3 commits into
mainfrom
fix-2685-eval-split-early-exit
Sep 2, 2026
Merged

fix(cli): fail fast when gym eval run --split has no matching dataset#2911
adil-a merged 3 commits into
mainfrom
fix-2685-eval-split-early-exit

Conversation

@adil-a

@adil-a adil-a commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What

Fixes #2685 ([VDR][v0.6.0] ERR-91baf7d3).

gym eval run --split train against a config with no train-typed dataset (e.g. example_single_tool_call, which ships only an example dataset) walked the entire data-preparation banner sequence, printed "View your final data!" and "# Finished!", and only then exited 1 on a bare assert input_jsonl_fpath.exists() whose message was an internal path (and which disappears under python -O).

Changes

  • Fail fast before preparation: validate that some loaded config declares a dataset of the requested split's type. The error lists the declared datasets and, when example datasets exist, prints the copy-pasteable documented recipe (gym eval run --no-serve --input <server>/data/example.jsonl).
  • Replace the bare assert with an explicit ConfigError backstop naming the split and the split files preparation actually produced (covers other missing-file causes: failed downloads, stale reuse_existing_data_preparation).
  • Actionable --split example rejection: caught before the pydantic Literal check with the documented gym env start + --no-serve --input flow, instead of a bare "Input should be 'train'". Per the discussion on [VDR][v0.6.0] ERR-91baf7d3 · gym eval run --split with no matching dataset prints "Finished!" then dies on a bare assert #2685, example datasets stay non-runnable via --split (they are the PR data gate's committed smoke-test samples); the suggested "let --input satisfy the serving path" change is deliberately not included — it reverses an intentional guard and deserves its own issue.
  • Latent bug fix in that guard: the CLI passes an OmegaConf DictConfig (a Mapping, not a dict), so the existing isinstance(data, dict) check in _reject_input_jsonl_fpath never fired on the real path and -i/--input was silently dropped when serving — exactly the failure it was written to prevent. Now matches on Mapping, with a DictConfig regression test.

New behavior

$ gym eval run --resources-server example_single_tool_call --model-type openai_model --split train -o out.jsonl
Error: No dataset of type `train` is declared in this config, so `--split train` has nothing to run.
Declared datasets:
- example_single_tool_call_simple_agent: example (type: example)
Example datasets are committed smoke-test samples and are not runnable via --split. To run one, start the servers (gym env start ...) and collect against the file directly:
  gym eval run --no-serve --input resources_servers/example_single_tool_call/data/example.jsonl --output <out>.jsonl

Testing

  • pytest tests/unit_tests/: 1264 passed (new: test_cli_eval.py, extended TestE2EInputJsonlFpathRejected, new TestE2EExampleSplitRejected).
  • Real CLI smoke test of both error paths against example_single_tool_call (output above; exit 1, no banners, no traceback).
  • pre-commit run on changed files: clean.

🤖 Generated with Claude Code

@copy-pr-bot

copy-pr-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@adil-a

adil-a commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 8f7f1d9

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🌿 Preview your docs: https://nvidia-preview-fix-2685-eval-split-early-exit.docs.buildwithfern.com/nemo/gym

Here are the markdown pages you've updated:

gym eval run --split train against a config that declares no train-typed
dataset (e.g. example_single_tool_call, which ships only an example
dataset) previously walked the entire data-preparation sequence, printed
its success banners, and only then died on a bare
`assert input_jsonl_fpath.exists()` whose message was an internal path
(and which disappears entirely under python -O).

- Validate up front that some config declares a dataset of the requested
  split's type; error with the declared datasets and, for example
  datasets, the copy-pasteable --no-serve --input recipe from the docs.
- Replace the bare assert with an explicit ConfigError backstop that
  lists which split files data preparation actually produced.
- Reject --split example before the pydantic Literal check with the
  documented gym env start + gym eval run --no-serve --input flow,
  instead of a bare "Input should be 'train'".
- Fix a latent bug in the serving-path --input rejection: the CLI passes
  an OmegaConf DictConfig, which is a Mapping but not a dict, so the
  isinstance(data, dict) guard never fired on the real path and
  input_jsonl_fpath was silently dropped — exactly the failure the
  validator was written to prevent. Match on Mapping instead.

Fixes #2685

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adil Asif <adasif@nvidia.com>
@adil-a
adil-a force-pushed the fix-2685-eval-split-early-exit branch from 8f7f1d9 to 0ebf761 Compare September 1, 2026 05:33
@adil-a

adil-a commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 0ebf761

@adil-a adil-a added the r0.6.0 Auto-cherrypick to release branch. Apply before merge; cherrypick happens after merge. label Sep 1, 2026
@anwithk
anwithk requested a review from ffrujeri September 1, 2026 16:28

@ffrujeri ffrujeri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for improving this failure mode. Failing before data preparation and replacing the user-facing assert with ConfigError are clear improvements.

I think the reported behavior also exposes a deeper semantic mismatch that is worth acknowledging, even if it is outside the scope of this fix. A command such as:

gym eval run --resources-server example_single_tool_call --split train

reads as “run the train split of this benchmark,” but a resources server is not itself a benchmark. It provides environment-side behavior such as tools, state, and verification, and it does not inherently need to own a train, validation, or benchmark dataset. In practice, the CLI composes several loaded configs and treats --split as a global request, with datasets potentially declared on an agent or resources server.

The validator in this PR correctly checks the complete loaded configuration rather than requiring the selected resources server itself to have the split. However, that also highlights that the CLI currently blurs three concepts:

  • the resources server (tools/state/verifier),
  • the dataset or benchmark tasks,
  • the complete environment configuration that composes resources, agent, model, and datasets.

I think this PR is a worthwhile backward-compatible guard for the current interface, but we should avoid wording that implies every resources server is a benchmark or must provide the requested split. The contract is instead: some dataset in the complete loaded configuration must match --split.

As a follow-up, it may be worth tracking a clearer environment/dataset-oriented CLI interface, where users select an environment/config and a named dataset directly rather than inferring dataset ownership through --resources-server plus --split.

Comment thread nemo_gym/cli/eval.py Outdated
f"Even though the `reuse_existing_data_preparation=true` flag was set, we will still do data preparation since the final input jsonl fpath `{input_jsonl_fpath}` does not exist yet"
)

server_instance_configs = GlobalConfigDictParser().filter_for_server_instance_configs(global_config_dict)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we run _validate_split_datasets_declared() before the should_skip_data_processing branch? As written, when reuse_existing_data_preparation=true and the expected split file already exists, the declaration check is skipped. That appears to allow a stale prepared file to run even when the current loaded configuration no longer declares that split. Is that intentional? If reuse is expected to bypass this validation, should the new documentation qualify its statement that a matching dataset “must be declared”?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll fix that

@ffrujeri
ffrujeri self-requested a review September 1, 2026 18:42
ffrujeri
ffrujeri previously approved these changes Sep 1, 2026

@ffrujeri ffrujeri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments worth taking a look. but otherwise I think we can proceed

…g prepared data

Hoist the declaration check above the reuse_existing_data_preparation
branch. Reuse skips the preparation work, not the request validation, so
a stale prepared file can no longer run for a split the loaded config no
longer declares.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Adil Asif <adasif@nvidia.com>
@adil-a

adil-a commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test a5309d7

@copy-pr-bot

copy-pr-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

/ok to test a5309d7

@adil-a, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@adil-a

adil-a commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test ee4fd8f

@adil-a
adil-a merged commit fa354f4 into main Sep 2, 2026
40 checks passed
@adil-a
adil-a deleted the fix-2685-eval-split-early-exit branch September 2, 2026 04:10
ananthsub pushed a commit that referenced this pull request Sep 2, 2026
…dataset (2911)` into `r0.6.0` (#2953)

beep boop [🤖]: Hi @adil-a 👋,

    we've cherry picked #2911 into  for you! 🚀

    Please review and approve this cherry pick by your convenience!

Signed-off-by: Adil Asif <adasif@nvidia.com>
Signed-off-by: NeMo Bot <nemo-bot@nvidia.com>
Co-authored-by: Adil <47084919+adil-a@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r0.6.0 Auto-cherrypick to release branch. Apply before merge; cherrypick happens after merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[VDR][v0.6.0] ERR-91baf7d3 · gym eval run --split with no matching dataset prints "Finished!" then dies on a bare assert

2 participants