Skip to content

fix(inference): fail-fast on empty model for cloud providers, demote nvidia-nim Sentry noise#2811

Open
staimoorulhassan wants to merge 3 commits into
tinyhumansai:mainfrom
staimoorulhassan:fix/nvidia-nim-model-field
Open

fix(inference): fail-fast on empty model for cloud providers, demote nvidia-nim Sentry noise#2811
staimoorulhassan wants to merge 3 commits into
tinyhumansai:mainfrom
staimoorulhassan:fix/nvidia-nim-model-field

Conversation

@staimoorulhassan
Copy link
Copy Markdown
Contributor

@staimoorulhassan staimoorulhassan commented May 28, 2026

Summary

Closes #2784.

make_cloud_provider_by_slug now rejects a zero-length effective model at factory construction time instead of silently forwarding model="" to the upstream API. Providers like nvidia-nim respond with {"error":{"message":"model field is required",...}} (400), and each agent turn generates a Sentry event (TAURI-RUST-4NM).

Root cause: In make_cloud_provider_by_slug, when the provider string is nvidia-nim: (empty model component) and the [[cloud_providers]] entry has no default_model, effective_model resolved to "". Nothing validated this before forwarding it in the API request body.

Changes:

  • factory.rs: After resolving effective_model, bail with a clear, actionable message if it's still empty (and the entry is not OpenhumanJwt — JWT entries route to the backend and never forward the model).
  • config_rejection.rs: Add "model field is required" to the PHRASES list as defense-in-depth.
  • factory_test.rs: Two new unit tests:
    • cloud_provider_with_no_model_and_no_default_rejected — empty provider string + no default_model → clear error naming the slug
    • cloud_provider_default_model_used_when_model_part_is_empty — empty provider string + has default_model → factory succeeds, resolves to default_model
  • config_rejection.rs tests: detects_nvidia_nim_missing_model_body pins the classifier against the real wire body.

Test plan

  • cargo test -p openhuman -- inference::provider::factory_test passes (two new tests + existing suite unchanged)
  • cargo test -p openhuman -- inference::provider::config_rejection::tests passes
  • Manually configure a [[cloud_providers]] entry with slug = "nvidia-nim" and no default_model; attempting to use nvidia-nim: shows the actionable error instead of a provider 400
  • Same entry with default_model = "meta/llama-3.1-8b-instruct" and provider string nvidia-nim: → factory uses the default model

Summary by CodeRabbit

  • Bug Fixes

    • Better detection of provider configuration errors by recognizing additional phrasing that indicates a missing model and classifying those as configuration issues.
    • Fail-fast validation reports clear errors when a resolved model name is empty, prompting users to supply a model or set a default.
  • Tests

    • Added regression tests for empty-model parsing and default-model fallback behavior.

Review Change Stack

…nvidia-nim Sentry noise

Fixes tinyhumansai#2784.

`make_cloud_provider_by_slug` now rejects a zero-length effective model
(provider string `nvidia-nim:` with no inline model AND no `default_model`
entry) at factory construction time instead of silently forwarding
`model=""` to the upstream API. Providers such as nvidia-nim respond with
`{"error":{"message":"model field is required",...}}` (400) and Sentry
accumulates one event per agent turn (TAURI-RUST-4NM).

Changes:
- `factory.rs`: bail with a clear, actionable message when
  `effective_model.trim().is_empty()` after resolution. Actionable path:
  either supply the model in the provider string (`nvidia-nim:<model-id>`)
  or set `default_model` in the `[[cloud_providers]]` config entry.
- `config_rejection.rs`: add "model field is required" to the
  `PHRASES` list as defense-in-depth so any body that still reaches
  the HTTP layer is demoted to `log::info!` rather than Sentry.
- `factory_test.rs`: two new unit tests —
  `cloud_provider_with_no_model_and_no_default_rejected` asserts the
  early-error path fires with a message naming the slug, and
  `cloud_provider_default_model_used_when_model_part_is_empty` asserts
  the happy-path fallback to `default_model` is preserved.
- `config_rejection.rs` tests: `detects_nvidia_nim_missing_model_body`
  pins the "model field is required" classifier.
@staimoorulhassan staimoorulhassan requested a review from a team May 28, 2026 04:49
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5bea9466-d952-4682-96d7-181c9fb5f159

📥 Commits

Reviewing files that changed from the base of the PR and between 6168e1c and 20a51ec.

📒 Files selected for processing (1)
  • src/openhuman/inference/provider/factory.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/openhuman/inference/provider/factory.rs

📝 Walkthrough

Walkthrough

Adds early validation to fail provider creation when the resolved model is empty (except for OpenhumanJwt auth) and expands the provider error classifier to recognize case-insensitive "model field is required" messages; includes regression/unit tests for both behaviors.

Changes

Cloud Provider Model Validation and Error Handling

Layer / File(s) Summary
Factory validation for empty models
src/openhuman/inference/provider/factory.rs, src/openhuman/inference/provider/factory_test.rs
Adds an early guard that fails when the resolved effective_model is empty (skips guard for AuthStyle::OpenhumanJwt); tests verify rejection without default_model and acceptance when default_model is set.
Config rejection classifier expansion
src/openhuman/inference/provider/config_rejection.rs
Extends is_provider_config_rejection_message to match the case-insensitive phrase "model field is required" and adds tests covering full nvidia-nim error body and the bare phrase.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • laith-max
  • senamakel

Poem

🐰 I hopped through code where models hid,
Found empty fields — that's what I did.
"Require a model!" the factory pleas,
The classifier hears nvidia's unease.
Now errors guide and tests are lit.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: fail-fast validation on empty model for cloud providers and reducing Sentry noise from nvidia-nim errors.
Linked Issues check ✅ Passed The PR addresses all acceptance criteria from #2784: prevents empty model fields in requests (factory.rs), eliminates Sentry noise via config_rejection.rs, adds comprehensive unit tests, and preserves other provider functionality.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #2784: model validation in factory.rs, error classification in config_rejection.rs, and corresponding unit tests in factory_test.rs.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. bug labels May 28, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 28, 2026
Three lines were formatted in a way cargo fmt rejects:
- config_rejection.rs: wrap bare assert! arg onto its own line
- factory_test.rs: inline `let err = match` (no line-break before match)
- factory_test.rs: inline `let (_, model) = call()` method chain
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 28, 2026
The empty-model bail! added in TAURI-RUST-4NM fired for openhuman:
(auth_style=OpenhumanJwt) slugs, breaking openhuman_slug_routes_to_backend.
OpenhumanJwt entries route to the OpenHuman backend and never forward the
effective_model to an upstream API, so an empty model is valid for that
auth style. Guard the check with auth_style != OpenhumanJwt.
@oxoxDev oxoxDev self-assigned this May 28, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

@staimoorulhassan hey! the code looks good to me — solid fix for the nvidia-nim Sentry noise. the fail-fast in make_cloud_provider_by_slug is the right call, and the tests cover both cases cleanly. the config_rejection.rs defense-in-depth phrase is a nice touch too.

however, the Rust Core Coverage (cargo-llvm-cov) CI job is failing (the Run cargo llvm-cov for openhuman core step itself, not a coverage threshold — so this may be an infra flake, but it's blocking the coverage gate from running entirely). once that's green, i'll come back and approve this. let me know if you need any help!

@oxoxDev oxoxDev removed their assignment May 28, 2026
@staimoorulhassan
Copy link
Copy Markdown
Contributor Author

Hi @graycyrus, thanks for the thorough review! The Rust Core Coverage (cargo-llvm-cov) failure is a pre-existing flaky test completely unrelated to this PR's changes:

thread 'openhuman::approval::gate::tests::pending_for_thread_tracks_request_under_chat_context_and_clears'
panicked at src/openhuman/approval/gate.rs:687
assertion failed: matches!(handle.await.unwrap(), GateOutcome::Allow)

Our PR only touches factory.rs, factory_test.rs, and config_rejection.rs — no changes to approval/gate.rs or anything in the approval domain. The test / Rust Core Tests + Quality job (which runs the same suite) passed cleanly on this PR, so the failure is a timing/race condition in the gate test that fires intermittently under llvm-cov's instrumented build (single-threaded, slower). A re-run should clear it.

Copy link
Copy Markdown
Contributor Author

@staimoorulhassan staimoorulhassan left a comment

Choose a reason for hiding this comment

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

@staimoorulhassan
Copy link
Copy Markdown
Contributor Author

Hi @graycyrus — the Rust Core Coverage job failed again with the same pre-existing race in approval/gate.rs:687 (the pending_for_thread_tracks_request_under_chat_context_and_clears test). This is unrelated to any changes in this PR; it surfaces intermittently under llvm-cov's single-threaded instrumented mode. Could you please trigger a re-run of that job? As an external fork contributor I can't re-run CI on this repo. All other checks pass clean. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nvidia-nim provider omits model field in API requests, causing 400 errors

3 participants