Repository navigation
Conversation
There was a problem hiding this comment.
2 issues found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/runtime/src/pipeline/network/egress/push_router.rs">
<violation number="1" location="lib/runtime/src/pipeline/network/egress/push_router.rs:64">
P2: The `CLIENT_REFUSAL` exclude set makes `is_inhibited` return `false` if *any* link in the chain is `InvalidArgument`, not just the outer pre-stream refusal. `is_inhibited` is also applied to mid-stream errors at lines 1948 and 1978, so any genuine worker fault (e.g. `CannotConnect`, `StreamIncomplete`, `ResponseTimeout`) whose cause chain happens to contain an `InvalidArgument` anywhere will now escape quarantine and keep being reselected. The pre-stream typed-refusal case is intended, but this suppresses inhibition for the whole chain regardless of the true outermost fault.</violation>
</file>
<file name="lib/runtime/src/pipeline/network/ingress/push_handler.rs">
<violation number="1" location="lib/runtime/src/pipeline/network/ingress/push_handler.rs:766">
P2: When the failure has no worker `DynamoError`, this always supplies `Some(ErrorType::Unknown)`, causing QUIC to emit typed JSON instead of the legacy raw UTF-8 error. Return an optional typed error and use `StreamPrologueError::from_message` when no worker error was recovered.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| let _ = publisher.send_prologue(Some(error_string)).await; | ||
| let prologue_error = StreamPrologueError::new( | ||
| error_string, | ||
| typed_error_from_pipeline_error(&error), |
There was a problem hiding this comment.
P2: When the failure has no worker DynamoError, this always supplies Some(ErrorType::Unknown), causing QUIC to emit typed JSON instead of the legacy raw UTF-8 error. Return an optional typed error and use StreamPrologueError::from_message when no worker error was recovered.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/runtime/src/pipeline/network/ingress/push_handler.rs, line 766:
<comment>When the failure has no worker `DynamoError`, this always supplies `Some(ErrorType::Unknown)`, causing QUIC to emit typed JSON instead of the legacy raw UTF-8 error. Return an optional typed error and use `StreamPrologueError::from_message` when no worker error was recovered.</comment>
<file context>
@@ -729,7 +761,11 @@ where
- let _ = publisher.send_prologue(Some(error_string)).await;
+ let prologue_error = StreamPrologueError::new(
+ error_string,
+ typed_error_from_pipeline_error(&error),
+ );
+ let _ = publisher.send_prologue_typed(Some(prologue_error)).await;
</file context>
| ErrorType::InvalidArgument, | ||
| ErrorType::Backend(BackendError::InvalidArgument), | ||
| ]; | ||
| match_error_chain(err, INHIBITED, CLIENT_REFUSAL) |
There was a problem hiding this comment.
P2: The CLIENT_REFUSAL exclude set makes is_inhibited return false if any link in the chain is InvalidArgument, not just the outer pre-stream refusal. is_inhibited is also applied to mid-stream errors at lines 1948 and 1978, so any genuine worker fault (e.g. CannotConnect, StreamIncomplete, ResponseTimeout) whose cause chain happens to contain an InvalidArgument anywhere will now escape quarantine and keep being reselected. The pre-stream typed-refusal case is intended, but this suppresses inhibition for the whole chain regardless of the true outermost fault.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/runtime/src/pipeline/network/egress/push_router.rs, line 64:
<comment>The `CLIENT_REFUSAL` exclude set makes `is_inhibited` return `false` if *any* link in the chain is `InvalidArgument`, not just the outer pre-stream refusal. `is_inhibited` is also applied to mid-stream errors at lines 1948 and 1978, so any genuine worker fault (e.g. `CannotConnect`, `StreamIncomplete`, `ResponseTimeout`) whose cause chain happens to contain an `InvalidArgument` anywhere will now escape quarantine and keep being reselected. The pre-stream typed-refusal case is intended, but this suppresses inhibition for the whole chain regardless of the true outermost fault.</comment>
<file context>
@@ -54,7 +54,14 @@ fn is_inhibited(err: &(dyn std::error::Error + 'static)) -> bool {
+ ErrorType::InvalidArgument,
+ ErrorType::Backend(BackendError::InvalidArgument),
+ ];
+ match_error_chain(err, INHIBITED, CLIENT_REFUSAL)
}
</file context>
Signed-off-by: Biswa Panda <biswa.panda@gmail.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/runtime/src/pipeline/network/quic_response.rs">
<violation number="1" location="lib/runtime/src/pipeline/network/quic_response.rs:300">
P2: An untyped JSON message containing the reserved `kind` and `error` fields is misclassified as the tagged envelope, even without a typed error. Require `typed_error` to be present before taking this branch so raw untyped messages remain byte-for-byte unchanged.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| fn decode_error_payload(payload: &[u8]) -> Result<StreamPrologueError> { | ||
| if payload.first() == Some(&b'{') | ||
| && let Ok(wire) = serde_json::from_slice::<QuicTypedErrorWire>(payload) | ||
| && wire.kind == QUIC_TYPED_ERROR_KIND |
There was a problem hiding this comment.
P2: An untyped JSON message containing the reserved kind and error fields is misclassified as the tagged envelope, even without a typed error. Require typed_error to be present before taking this branch so raw untyped messages remain byte-for-byte unchanged.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/runtime/src/pipeline/network/quic_response.rs, line 300:
<comment>An untyped JSON message containing the reserved `kind` and `error` fields is misclassified as the tagged envelope, even without a typed error. Require `typed_error` to be present before taking this branch so raw untyped messages remain byte-for-byte unchanged.</comment>
<file context>
@@ -244,46 +244,65 @@ impl Frame {
- && let Ok(prologue) = serde_json::from_slice::<ResponseStreamPrologue>(payload)
- && let Some(message) = prologue.error
+ && let Ok(wire) = serde_json::from_slice::<QuicTypedErrorWire>(payload)
+ && wire.kind == QUIC_TYPED_ERROR_KIND
+ && let Some(message) = wire.prologue.error
{
</file context>
| && wire.kind == QUIC_TYPED_ERROR_KIND | |
| && wire.kind == QUIC_TYPED_ERROR_KIND | |
| && wire.prologue.typed_error.is_some() |
Automated refresh from the public Dynamo Google Calendar. Generated by .github/workflows/community-events-refresh.yml. Signed-off-by: dynamo-ops <170655669+dynamo-ops@users.noreply.github.com>
…mo#14618) Signed-off-by: Yingge He <yinggeh@nvidia.com>
…dynamo#14836) Signed-off-by: xianlubird <xianlubird@gmail.com>
…lease 1.5.0 (ai-dynamo#14840) Signed-off-by: Biswa Panda <biswa.panda@gmail.com>
…i-dynamo#14635) Signed-off-by: Codex <codex@openai.com> Signed-off-by: vanshil shah <49670736+vanshilshah97@users.noreply.github.com> Co-authored-by: Codex <codex@openai.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
…14855) Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
…amo#14449) Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com>
Signed-off-by: William Arnold <7565007+Aphoh@users.noreply.github.com>
… supports them (ai-dynamo#14835) Signed-off-by: Vinya567 <vinyak@nvidia.com>
…ai-dynamo#14563) Signed-off-by: nnshah1 <neelays@nvidia.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Dmitry Tokarev <dtokarev@nvidia.com>
…dynamo#14364) Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com> Signed-off-by: GLAMR <svc-glamr@nvidia.com> Co-authored-by: Dan Gil <dagil@nvidia.com> Co-authored-by: yunzhoul-nv <232973175+yunzhoul-nv@users.noreply.github.com>
…mo#14797) Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com> Signed-off-by: Schwinn Saereesitthipitak <schwinns@nvidia.com> Signed-off-by: GLAMR <svc-glamr@nvidia.com> Co-authored-by: Schwinn Saereesitthipitak <schwinns@nvidia.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
…ENV (ai-dynamo#14865) Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…es (ai-dynamo#14455) Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com> Signed-off-by: Biswa Panda <biswa.panda@gmail.com> Co-authored-by: Biswa Panda <biswa.panda@gmail.com> Co-authored-by: yunzhoul-nv <232973175+yunzhoul-nv@users.noreply.github.com>
…4564) Signed-off-by: krishung5 <krish@nvidia.com>
…14671) Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Add live-reloaded file sources for KV DC Relay namespace selection and expose readiness and source revisions through /engine/state. Preserve applied membership on invalid updates, coalesce discovery refreshes, and isolate native integration tests in forked processes. Signed-off-by: Nikita Sukharev <kaonael@gmail.com>
…ynamo#14032) Signed-off-by: xianlubird <xianlubird@gmail.com>
…i-dynamo#14860) Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Signed-off-by: William Arnold <7565007+Aphoh@users.noreply.github.com> Co-authored-by: Zero Rains <57100978+zeroRains@users.noreply.github.com>
…d recipes for B200 (ai-dynamo#14376) Signed-off-by: Sandhya Rani Narravula <snarravula@nvidia.com>
…LM (ai-dynamo#14428) Signed-off-by: Karen Chung <karenc@nvidia.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
Automated refresh from the public Dynamo Google Calendar. Generated by .github/workflows/community-events-refresh.yml. Signed-off-by: dynamo-ops <170655669+dynamo-ops@users.noreply.github.com>
Signed-off-by: J Wyman <jwyman@nvidia.com>
Signed-off-by: furionw <qiwa@nvidia.com>
…-dynamo#14676) Signed-off-by: Dao007forever <daole@inferact.ai> Signed-off-by: krishung5 <krish@nvidia.com> Signed-off-by: furionw <qiwa@nvidia.com> Co-authored-by: Dao007forever <daole@inferact.ai> Co-authored-by: krishung5 <krish@nvidia.com> Co-authored-by: furionw <qiwa@nvidia.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ai-dynamo#15090) Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com> Signed-off-by: GLAMR <svc-glamr@nvidia.com>
…mount (ai-dynamo#13048) Signed-off-by: Dan Gil <dagil@nvidia.com>
Signed-off-by: Ryan McCormick <rmccormick@nvidia.com>
…i-dynamo#15237) Signed-off-by: Kan Wu <wukanustc@gmail.com> Co-authored-by: Ryan McCormick <rmccormick@nvidia.com>
Signed-off-by: dynamo-ops <170655669+dynamo-ops@users.noreply.github.com> Signed-off-by: Dmitry Tokarev <dtokarev@nvidia.com> Signed-off-by: tanmayv25 <tanmay2592@gmail.com> Co-authored-by: Dmitry Tokarev <dtokarev@nvidia.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: tanmayv25 <tanmay2592@gmail.com>
Signed-off-by: Kan Wu <wukanustc@gmail.com>
Signed-off-by: Ace Eldeib <aeldeib@coreweave.com> Signed-off-by: thuanpham582002 <tienthuan05082002@gmail.com> Co-authored-by: thuanpham582002 <tienthuan05082002@gmail.com>
…i-dynamo#14181) Signed-off-by: Jorge Antonio <matroid@outlook.com> Co-authored-by: Ryan McCormick <rmccormick@nvidia.com>
88883d5 to
edbee96
Compare
QUIC Error frames were still raw UTF-8, so a worker ErrorType was dropped. Tag typed payloads with dynamo.quic.typed_error and leave untagged JSON as the legacy message. Co-authored-by: Prudctual <Prudctual@users.noreply.github.com> Signed-off-by: Jasim Kareem <219012065+Prudctual@users.noreply.github.com>
edbee96 to
cfbd80c
Compare
Overview:
QUIC (
DYN_RESPONSE_PLANE=quic) could not carry a worker'sErrorTypeon a pre-stream refusal. The frontend therefore answered HTTP500and fault detection quarantined the worker that had correctly refused the request. TCP already maps the same refusal to400once the typed prologue exists; this PR extends that path to QUIC with a mixed-version Error-frame encoding.Details:
QuicResponseSendersentFrameKind::Erroras raw UTF-8, soResponsePublisher::send_prologue_typedhad nowhere to put aDynamoError. The requesting side re-synthesizedErrorType::CannotConnectwith no cause, which the frontend maps to a sanitized500andis_inhibitedtreats as a worker fault.This PR:
StreamPrologueErrorand an optionaltyped_erroronResponseStreamPrologue(skipped when absent so an old sender still handshakes).ResponseStreamPrologue. Untyped errors stay raw UTF-8. Receivers accept both: JSON with a presenterrorfield recovers the type; anything else, including a Python{"message","code"}envelope, is the legacy message. Protocol version stays 3 — a bump would force a lockstep upgrade for a payload the old decoder already accepts as UTF-8.send_prologue_typedon both QUIC and TCP so the worker's type survives whichever response plane is configured.CannotConnect, so HTTP classification seesInvalidArgumentwhile retry classification of the outer type is unchanged.InvalidArgument/Backend(InvalidArgument)fromis_inhibited, so a clean client refusal does not quarantine the worker. An untyped pre-stream failure still does.TCP untyped behaviour is unchanged: an old worker that sends only display text still yields
500and is still treated as a worker fault.Public API:
StreamProvider<T>widens its error fromStringtoStreamPrologueError.StreamPrologueErrorderefs tostr, soerr.contains(..),err.len(), and&err[..]keep compiling. This overlaps the runtime plumbing in ai-dynamo#14467; this PR is self-contained against currentmainso QUIC can land without waiting on that review. If ai-dynamo#14467 merges first, this rebases onto the shared types.Where should the reviewer start?
lib/runtime/src/pipeline/network/quic_response.rs—encode_error_payload/decode_error_payloadandsend_prologue_typedlib/runtime/src/pipeline/network.rs—ResponseStreamPrologue.typed_errorandStreamPrologueErrorlib/runtime/src/pipeline/network/egress/addressed_router.rs—pre_stream_failure_errorlib/runtime/src/pipeline/network/egress/push_router.rs—is_inhibitedclient-refusal excludeValidation
cargo fmt --all -- --checkcargo clippy -p dynamo-runtime --lib --all-targets -- -D warningscargo test -p dynamo-runtime --lib pipeline::network::quic_response::tests— 26 passed (includes typed Error-frame round trip, livesend_prologue_typed→InvalidArgument, and legacy UTF-8)cargo test -p dynamo-runtime --lib pipeline::network::tcp::server::tests— 40 passed (TCP typed prologue survives; untyped/invalid-prologue paths unchanged)cargo test -p dynamo-llm --lib test_pre_stream_refusal_surfaces_as_400 test_pre_stream_connect_failure_still_surfaces_as_500— typed pre-stream refusal → HTTP400with the worker's reason; untyped / engine-shutdown still500typed_client_refusal_does_not_quarantine_the_worker—CannotConnect+InvalidArgumentcause is not inhibited; untypedCannotConnectstill isRelated Issues
🔗 This PR is linked to an issue:
main)AI disclosure
This change was drafted with assistance from Cursor Grok 4.6. I reviewed the wire-format compatibility, the quarantine/
is_inhibitedinteraction, and the test results before opening the PR.Summary by cubic
Carries the worker's typed error on the QUIC response plane so a clean client refusal gets HTTP 400 instead of HTTP 500 and is no longer treated as a worker fault. Untyped pre-stream failures still surface as HTTP 500 and quarantine the worker.
Note: this branch is far behind main and has not been rebased — the diff carries ~150 unrelated commits. Rebase before merging; only the QUIC typed-error work below belongs to this PR.
dynamo.quic.typed_error; anything untagged (legacy UTF-8, Python{"message","code"}envelopes, decoy{"error","code"}objects) stays raw UTF-8 so it can't be misparsed as a prologue. Protocol version stays 3.InvalidArgument/Backend(InvalidArgument)) are excluded fromis_inhibited, andNON_MIGRATABLEis pinned to the same set so an attached cause never changes migration behavior.Migration
StreamProvider<T>'s error type widens fromStringtoStreamPrologueError; it derefs tostr, so.contains(),.len(), and indexing keep compiling.Written for commit cfbd80c. Summary will update on new commits.