Skip to content

Commit 891e02e

Browse files
fix(executor): stop adopting an upstream target's HTTP status as our own
1 parent 67805cb commit 891e02e

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

apps/sim/executor/utils/errors.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,15 @@ describe('getExecutionErrorStatus', () => {
4545
expect(getExecutionErrorStatus(new Error('boom'))).toBe(500)
4646
})
4747

48-
it('reads the legacy duck-typed status field', () => {
49-
const error = Object.assign(new Error('rate limited'), { status: 429 })
48+
it("never adopts an upstream target's duck-typed status as our own", () => {
49+
// `api-handler` copies the remote response's status onto the thrown error.
50+
// Adopting it would make a remote 404 the workflow API's 404.
51+
const error = Object.assign(new Error('HTTP 404'), { status: 404 })
52+
expect(getExecutionErrorStatus(error)).toBe(500)
53+
})
54+
55+
it('still reads a Sim-owned statusCode re-attached from a ToolResponse', () => {
56+
const error = Object.assign(new Error('rate limited'), { statusCode: 429 })
5057
expect(getExecutionErrorStatus(error)).toBe(429)
5158
})
5259

apps/sim/executor/utils/errors.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,14 @@ const MAX_CAUSE_DEPTH = 8
7676
/**
7777
* HTTP status carried by a thrown value, walking the `.cause` chain so a status
7878
* set deep in a tool survives the block-level wrapping that rebuilds the error.
79-
* Reads `HttpError.statusCode` (the canonical class-based carrier) plus the
80-
* legacy duck-typed `statusCode`/`status` fields some paths still set.
79+
*
80+
* Reads only SIM-OWNED carriers: `HttpError.statusCode` (canonical) and the
81+
* `statusCode` field `generic-handler` re-attaches from a failed `ToolResponse`.
82+
* Deliberately does NOT read the duck-typed `status` field: that carries an
83+
* UPSTREAM target's status (`api-handler` copies it off the remote response, and
84+
* transformed HTTP tool errors carry it too). Adopting it would turn a remote
85+
* 404 into the workflow API's 404, colliding with the statuses that route owns
86+
* (404 = workflow not found, 401 = bad API key, 429 = Sim rate limit).
8187
*/
8288
export function readStatusCode(value: unknown): number | undefined {
8389
const seen = new Set<unknown>()
@@ -89,9 +95,8 @@ export function readStatusCode(value: unknown): number | undefined {
8995

9096
if (current instanceof HttpError) return current.statusCode
9197

92-
const candidate = current as unknown as { statusCode?: unknown; status?: unknown }
98+
const candidate = current as unknown as { statusCode?: unknown }
9399
if (typeof candidate.statusCode === 'number') return candidate.statusCode
94-
if (typeof candidate.status === 'number') return candidate.status
95100

96101
current = current.cause
97102
}

0 commit comments

Comments
 (0)