Repository navigation
fix(sdk): always attach Response on HTTPError - #2668
Christian Bromann (christian-bromann) merged 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 36c64db The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@langchain/langgraph-checkpoint
@langchain/langgraph-checkpoint-mongodb
@langchain/langgraph-checkpoint-postgres
@langchain/langgraph-checkpoint-redis
@langchain/langgraph-checkpoint-sqlite
@langchain/langgraph-checkpoint-validation
create-langgraph
@langchain/langgraph-api
@langchain/langgraph-cli
@langchain/langgraph
@langchain/langgraph-cua
@langchain/langgraph-supervisor
@langchain/langgraph-swarm
@langchain/langgraph-ui
@langchain/langgraph-sdk
@langchain/angular
@langchain/react
@langchain/svelte
@langchain/vue
commit: |
|
Matches the proposed fix in the issue (option 2 — always Nit on the changeset: "even when onFailedResponseHook is unset" reads like the Also curious: is |
`AsyncCaller` attached the failed `Response` to `HTTPError` only when an `onFailedResponseHook` was registered, so `error.response` was `undefined` for everyone else. Inspecting a failure meant registering a hook whose real purpose is retry side effects, and the coupling was invisible from the outside. `includeResponse` is now always true. `HTTPError` is constructed in exactly one place — the `isResponse(error)` branch — so every `HTTPError` the SDK throws carries its `Response`. Failures that have no `Response` are unaffected: a generic rejection is rethrown as-is and a connection failure is replaced by `ConnectionError`, neither of which is an `HTTPError`, and both of which are pinned by a test so the boundary stays explicit. This is option 2 from the discussion on langchain-ai#2632 — attach unconditionally rather than widen the hook. 17 SDK caller tests pass; the `error.response` regression fails against the current `async_caller.ts`. Fixes langchain-ai#2632
134b4e8 to
36c64db
Compare
|
Thanks Denys Korolkov · Founder @ Routine Run (@denyskorolkov) — both taken. Changeset. You're right, the hook has no role post-fix and mentioning it in the changelog only implies otherwise. Now just:
The historical coupling stays in the PR description. On A failure with no
Neither carries I added a test pinning that boundary, since it's exactly the question a future reader will have: it("should not attach a response to failures that carry none", async () => {
// TypeError("boom") → rethrown as-is; TypeError("fetch failed") → ConnectionError
expect(error).not.toHaveProperty("response");
expect(error).not.toHaveProperty("status");
});Writing it corrected my own assumption, incidentally — I expected 17 caller tests pass, and the |
Thanks for doing this and sharing the ConnectionError catch, glad it's pinned in a test now. Contribution looks great. |
|
Thanks Denys Korolkov · Founder @ Routine Run (@denyskorolkov) — appreciate the review and the green light. Happy to iterate if anything else comes up before merge. |
Christian Bromann (christian-bromann)
left a comment
There was a problem hiding this comment.
Thank you , LGTM 👍
f9c0e88
into
langchain-ai:main
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @langchain/langgraph-sdk@1.9.29 ### Patch Changes - [#2668](#2668) [`f9c0e88`](f9c0e88) Thanks [@edenbuilds](https://github.com/edenbuilds)! - Always attach the underlying Response on HTTPError. - [#2675](#2675) [`3958305`](3958305) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): deliver input channel events on the root-bus fast path `channelProjection` with `replay: false` (the `useChannelEffect` default) compared `event.method` to channel names, so `input.requested` never matched `"input"`. Match via `inferChannel` instead, same as the slow path. - [#2677](#2677) [`4c0fd78`](4c0fd78) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): defer stream join until lazy thread create commits Hydrating an externally-minted thread id that 404s still opened `/stream/events` before `POST /commands` created the row. On langgraph_api's in-mem runtime that join is accepted but dead, so the first run delivered nothing until idle reconnect. Treat missing threads like client-minted ones and start the root pump only after dispatch succeeds. - [#2672](#2672) [`5be518f`](5be518f) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): surface nested interrupts on stream.interrupts `input.requested` events from subgraphs/subagents were dropped live by a root-only filter, while hydrate seeded them from `state.tasks`, so HITL UIs saw nested interrupts only after reload. Mirror every namespace onto `rootStore.interrupts` (with `Interrupt.namespace`), and resolve that namespace in `respond({ interruptId })` when callers omit it. - [#2676](#2676) [`b3c1ceb`](b3c1ceb) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): resolve respond() namespace from interrupt id When callers pass `{ interruptId }` without `namespace`, look the namespace up on `thread.interrupts` instead of defaulting to root. ## @langchain/angular@1.0.30 ### Patch Changes - [#2676](#2676) [`b3c1ceb`](b3c1ceb) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): resolve respond() namespace from interrupt id When callers pass `{ interruptId }` without `namespace`, look the namespace up on `thread.interrupts` instead of defaulting to root. - Updated dependencies [[`f9c0e88`](f9c0e88), [`3958305`](3958305), [`4c0fd78`](4c0fd78), [`5be518f`](5be518f), [`b3c1ceb`](b3c1ceb)]: - @langchain/langgraph-sdk@1.9.29 ## @langchain/react@1.0.30 ### Patch Changes - [#2676](#2676) [`b3c1ceb`](b3c1ceb) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): resolve respond() namespace from interrupt id When callers pass `{ interruptId }` without `namespace`, look the namespace up on `thread.interrupts` instead of defaulting to root. - Updated dependencies [[`f9c0e88`](f9c0e88), [`3958305`](3958305), [`4c0fd78`](4c0fd78), [`5be518f`](5be518f), [`b3c1ceb`](b3c1ceb)]: - @langchain/langgraph-sdk@1.9.29 ## @langchain/svelte@1.0.30 ### Patch Changes - [#2676](#2676) [`b3c1ceb`](b3c1ceb) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): resolve respond() namespace from interrupt id When callers pass `{ interruptId }` without `namespace`, look the namespace up on `thread.interrupts` instead of defaulting to root. - Updated dependencies [[`f9c0e88`](f9c0e88), [`3958305`](3958305), [`4c0fd78`](4c0fd78), [`5be518f`](5be518f), [`b3c1ceb`](b3c1ceb)]: - @langchain/langgraph-sdk@1.9.29 ## @langchain/vue@1.0.30 ### Patch Changes - [#2676](#2676) [`b3c1ceb`](b3c1ceb) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(sdk): resolve respond() namespace from interrupt id When callers pass `{ interruptId }` without `namespace`, look the namespace up on `thread.interrupts` instead of defaulting to root. - Updated dependencies [[`f9c0e88`](f9c0e88), [`3958305`](3958305), [`4c0fd78`](4c0fd78), [`5be518f`](5be518f), [`b3c1ceb`](b3c1ceb)]: - @langchain/langgraph-sdk@1.9.29 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
includeResponse: truewhen converting failedResponseobjects toHTTPError, soerror.responseis available without registeringonFailedResponseHook.Test plan
should attach error.response without onFailedResponseHookpasses with the fixresponse: undefinedwhen the fix is stashed (git stashA/B)@langchain/langgraph-sdkFixes #2632