Skip to content

fix(gateway): non-404 parameter errors win over NOT_FOUND across nodes#540

Merged
mfaferek93 merged 3 commits into
mainfrom
fix/param-error-precedence
Jul 17, 2026
Merged

fix(gateway): non-404 parameter errors win over NOT_FOUND across nodes#540
mfaferek93 merged 3 commits into
mainfrom
fix/param-error-precedence

Conversation

@mfaferek93

@mfaferek93 mfaferek93 commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

GET /{entity-path}/configurations/{param} probes every backing node and overwrote last_result on each failure, so node iteration order decided the surfaced error: a NOT_FOUND from one node masked a timeout/unavailable from another and the client saw 404 instead of 503.

Failures now fold through ParameterErrorAccumulator: non-404 errors win and a 404 never replaces a held non-404. New gtest pins the 503 outcome for TIMEOUT plus NOT_FOUND in both iteration orders.

Tested: colcon build + colcon test for ros2_medkit_gateway in the jazzy image (2506 tests, 0 failures);

Closes #539

The multi-node GET probe overwrote last_result on every failure, so a
NOT_FOUND from a later node masked a timeout/unavailable from an earlier
one and the client got 404 instead of 503. Fold failures through
ParameterErrorAccumulator so the surfaced error is order independent.
Copilot AI review requested due to automatic review settings July 16, 2026 20:00

Copilot AI 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.

Pull request overview

This PR fixes multi-node parameter GET error precedence in ros2_medkit_gateway so that non-404 failures (e.g., TIMEOUT / SERVICE_UNAVAILABLE) deterministically override NOT_FOUND regardless of backing-node iteration order, addressing issue #539.

Changes:

  • Introduce handlers::ParameterErrorAccumulator to fold per-node get_parameter() failures with “non-404 wins over 404” precedence.
  • Update ConfigHandlers::get_configuration() to use the accumulator instead of “last failure wins”.
  • Add a new GTest target to pin the 503 outcome for TIMEOUT + NOT_FOUND in both iteration orders.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp Uses ParameterErrorAccumulator during multi-node GET probing so non-404 failures cannot be masked by later 404s.
src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/config_handlers.hpp Defines ParameterErrorClassification and ParameterErrorAccumulator used to enforce error precedence.
src/ros2_medkit_gateway/test/test_parameter_error_precedence.cpp Adds regression tests validating precedence behavior independent of node iteration order.
src/ros2_medkit_gateway/CMakeLists.txt Registers and enables the new test_parameter_error_precedence target.

@mfaferek93 mfaferek93 self-assigned this Jul 17, 2026

@bburda bburda left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Additional findings outside the diff:

  • The only new test drives ParameterErrorAccumulator in isolation; nothing exercises get_configuration's multi-node branch, so the four unit tests stay green even if the handler wiring regressed to the old overwrite. The precedence only fires on GET /{aggregated-entity}/configurations/{param} (no app: prefix) with two or more backing nodes where one is unavailable and another lacks the parameter. An integration test on that path in both node orders would prove the fix.
  • Related: the accumulator and ParameterErrorClassification were lifted into the public handler header only so that test can drive them directly (no other translation unit uses them). Keeping the accumulator in the .cpp anonymous namespace and covering precedence through a handler-level test would tighten the public surface and close the proof gap.
  • Semantics (deliberate): there is no signal distinguishing "absent on all reachable nodes, one unreachable" from a bare 503, so a client probing whether a knob exists on a partially-down aggregated entity gets a retryable 503 for a parameter that may be terminally absent.
  • Pre-existing, out of scope: list_configurations returns 200 and silently drops a down backing node, while get /{param} for a parameter only on that node now returns 503. And the string fallback in classify_parameter_error (the error_code == NONE path) is dead on the shipped transport; if it were reached, the transport's real "did not respond" / "not currently set" messages do not contain its match substrings, so it would misclassify to 400.

Comment thread src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp Outdated
Among distinct non-404 failures the last one folded won, so a
partially-broken aggregated entity surfaced 503 or 500 depending on
node iteration order. Rank 503 > other 5xx > non-404 4xx > 404 and
keep the first failure at the winning rank.
Replace the accumulator-only unit tests with ConfigHandlers::get_configuration
tests against a live GatewayNode (unavailable, unresponsive and reachable
backing nodes, both iteration orders) and move ParameterErrorAccumulator back
into the .cpp anonymous namespace so no test-only surface leaks from the header.
@mfaferek93
mfaferek93 merged commit 6a7d6d9 into main Jul 17, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameter error aggregation: NOT_FOUND from one node masks timeout/unavailable from another

3 participants