fix(observability,embeddings): demote Ollama embed user-config rejections (Sentry TAURI-RUST-XS + MA/KM/GX)#2612
Conversation
Adds a dedicated matcher in the Sentry classifier ladder for Ollama
embed user-config rejections. Routes four wire shapes to the existing
ProviderUserState bucket:
- TAURI-RUST-XS (~376 events, self-hosted Sentry): user pointed the
embedder at a chat / vision model id, sometimes with a temperature
suffix (`qwen3-vl:4b@0.7`) Ollama parses as malformed. 400 Bad
Request with `{"error":"invalid model name"}`.
- OPENHUMAN-TAURI-MA / -KM (deferred follow-up from PR tinyhumansai#2216): user
configured a model the local daemon hasn't pulled. 404 Not Found
with `{"error":"model \"<id>\" not found, try pulling it first"}`.
- OPENHUMAN-TAURI-GX: user opted into Ollama embeddings but the
daemon isn't running. Wire shape:
`ollama embeddings opted-in but daemon unreachable at <url>; falling
back to cloud embeddings for this session`.
All four are user-config: wrong model id, model not pulled, or daemon
not started. The UI already surfaces actionable errors via toast /
settings warning; Sentry has no remediation path.
Wiring: insert the matcher in `expected_error_kind` after
`is_loopback_unavailable` and before `is_network_unreachable_message`
so the `ollama embed` / `ollama embeddings opted-in` prefix anchors
fire before the broader transport-failure classifiers. Routes to the
existing ProviderUserState variant (matching composio / gmail / OAuth
user-state errors) rather than introducing a new enum variant — the
demotion semantics are identical.
Unit tests cover the four positive wire shapes (with one variant
carrying the temperature-suffix model id) plus four negative shapes
(500 server error, parse failure, dimension mismatch, unrelated
`model "…" not found` outside the Ollama embed prefix).
…re shapes Flips the three deferred pinning tests from PR tinyhumansai#2216 (Lane K follow-up) to assert the demotion now lands, and adds two new positive XS cases plus a dimension-mismatch negative. - `ma_wire_shape_classifies_as_provider_user_state` (was `ma_wire_shape_current_state_unclassified`) — 404 model-not-found pull-required. - `km_wire_shape_classifies_as_provider_user_state` (was `km_wire_shape_current_state_unclassified`) — same shape, `:latest` tag variant. - `gx_wire_shape_classifies_as_provider_user_state` (was `gx_wire_shape_current_state_unclassified`) — daemon-unreachable opt-in state. - `xs_wire_shape_classifies_as_provider_user_state` (new) — canonical TAURI-RUST-XS 400 invalid-model-name wire shape. - `xs_temperature_suffix_model_classifies_as_provider_user_state` (new) — XS variant where the user pasted a model id with a temperature suffix like `qwen3-vl:4b@0.7`. - `ollama_500_wire_shape_stays_unexpected` (new) — server-side bug must still reach Sentry. - `ollama_dimension_mismatch_stays_unexpected` (new) — dim mismatch is a real desync bug, must still reach Sentry. - `gp_wire_shape_classifies` and `ollama_parse_error_wire_shape_stays_unexpected` retained verbatim — locks GP demotion + parse-error escape unchanged. These tests verify the integration end-to-end: the embed call site already routes through `report_error_or_expected` (added by PR tinyhumansai#2216), and the classifier now matches the wire shapes the call site emits.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe PR improves Ollama embedding error classification by adding a specialized detector ChangesOllama User-Config Rejection Classification
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
CI statusTwo failures on the latest run, both unrelated to this PR's diff (
|
Summary
is_ollama_user_config_rejectionmatcher to the Sentry classifier ladder insrc/core/observability.rs, routing four Ollama-embed user-config wire shapes (XS, MA, KM, GX) to the existingExpectedErrorKind::ProviderUserStatebucket.qwen3-vl:4b@0.7).report_error_or_expectedbut explicitly left the matcher arm open pending PR fix(observability): demote loopback sidecar-down noise to expected (#R5 #R6) #2063 + test(observability): pin SESSION_EXPIRED wire-shape regression tests (#SG) #2188 merging; both gating PRs landed 2026-05-19/20 and this PR closes the gap.src/openhuman/embeddings/ollama_tests.rsthat locked the prior unclassified state, and adds two new positive XS cases plus dimension-mismatch / 500-server-error negatives.Problem
Self-hosted Sentry is collecting
~376events forTAURI-RUST-XSwith the canonical body:These come from users who configured the embedding provider with a chat / vision model id (sometimes with a temperature suffix like
qwen3-vl:4b@0.7) that Ollama parses as malformed. The UI already surfaces an actionable error in the Settings → Embeddings page; Sentry has no remediation path because the request was malformed by the user's input, not by our code.Three sibling wire shapes —
OPENHUMAN-TAURI-MA,OPENHUMAN-TAURI-KM,OPENHUMAN-TAURI-GX— share the same "user-config rejection" semantics but escape capture today because the classifier ladder has no arm for them. PR #2216 (Lane K, merged 2026-05-20) routed the call sites throughreport_error_or_expectedbut explicitly deferred adding the matcher arm to a follow-up gated on PR #2063 + #2188 merging. Both gating PRs merged 2026-05-19/20 and the follow-up was never opened — this PR closes that gap.The three existing pinning tests at
src/openhuman/embeddings/ollama_tests.rs:339-378(named*_current_state_unclassified) lock the current escape-to-Sentry state with comments pointing at this exact follow-up.Solution
Add a single matcher
is_ollama_user_config_rejection(lower: &str) -> booltosrc/core/observability.rsthat anchors on theollama embed failed/ollama embeddings opted-inprefixes plus one of three body anchors:"invalid model name"(XS — 400 Bad Request)"model \"…\" not found"(MA / KM — 404 Not Found, pull-required)"opted-in but daemon unreachable at"(GX — daemon not running)Wire the matcher into
expected_error_kindafteris_loopback_unavailableand beforeis_network_unreachable_message. The GX wire shape containslocalhost:(a loopback host) but noConnection refused (os error N)marker, so it would otherwise fall through the loopback arm. Inserting before the network-unreachable arm gives the Ollama prefix anchors first dibs.Route the matches to the existing
ExpectedErrorKind::ProviderUserStatevariant (the same bucket holding the composio / gmail / OAuth user-state errors) rather than introducing a new variant. The demotion semantics (drop toinfolog, skip Sentry capture) are identical and adding a per-provider variant would balloon the enum without changing behavior.No call-site changes — PR #2216 already routed
src/openhuman/embeddings/ollama.rs:247-279throughreport_error_or_expected. Verified the route is still in place on this branch.Tests:
src/core/observability.rs::tests::classifies_ollama_user_config_rejections— five positive wire shapes (XS canonical, XS with temperature-suffix model, MA, KM, GX).src/core/observability.rs::tests::does_not_classify_unrelated_ollama_errors_as_user_config— four negatives (500 server error, parse failure, dimension mismatch, unrelatedmodel "…" not foundwithout theollama embedprefix).src/openhuman/embeddings/ollama_tests.rs— three flipped pinning tests ({ma,km,gx}_wire_shape_classifies_as_provider_user_state), two new XS positives, two new negatives (ollama_500_wire_shape_stays_unexpected,ollama_dimension_mismatch_stays_unexpected). The GP test (LocalAiCapabilityUnavailable) and parse-error escape test are retained verbatim.Submission Checklist
is_ollama_user_config_rejectionand the wiring is exercised by the new positive + negative unit tests in bothobservability::testsandembeddings::ollama::tests.Closes #NNN— Sentry-only triage; theSentry-Issue:headers in## Relatedprovide the trail.Impact
infobreadcrumb instead of an error event).lower.contains(...)substring checks per classification, all short-circuited on theollama embed/ollama embeddings opted-inprefix.report_error_or_expected.resolvedand bookmark MA/KM/GX for the 7-day regression-watch window.Related
report_error_or_expectedbut explicitly deferred the matcher arm pending PR fix(observability): demote loopback sidecar-down noise to expected (#R5 #R6) #2063 + test(observability): pin SESSION_EXPIRED wire-shape regression tests (#SG) #2188 merging (both merged 2026-05-19/20).[composio-direct]401 / Invalid API key with the sameProviderUserStatebucket strategy.CI note — pre-existing main FE failure
Three frontend jobs (
Frontend Coverage,Frontend Unit Tests,i18n Coverage) are red onupstream/mainsince 2026-05-21 due to PR #2378 (German locale missing 20 MCP-Server keys). This PR touches zero frontend files (Rust-only:src/core/observability.rs+src/openhuman/embeddings/ollama_tests.rs) and inherits the failure. PR #2481 merged through the same state — please apply the same precedent here.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/sentry-xs-ollama-classifier-armb4bd3da26a342fb4a4051083442db93424668987Validation Run
pnpm --filter openhuman-app format:check— no frontend files touchedpnpm typecheck— no frontend files touchedcargo test --lib core::observability(88 passed) +cargo test --lib openhuman::embeddings::ollama(36 passed)cargo fmt --checkclean;cargo check --manifest-path Cargo.tomlclean (pre-existing warnings only);cargo clippy --libno new warnings on changed codeValidation Blocked
Behavior Changes
infobreadcrumb instead.Parity Contract
ollama embedprefix prevents collisions with unrelated 400/404 error envelopes elsewhere in the codebase.does_not_classify_unrelated_ollama_errors_as_user_config). The matcher routes to the existingProviderUserStatevariant —report_expected_messagealready has the correct demotion path for that variant.Duplicate / Superseded PR Handling
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests