Skip to content

Commit 717ed80

Browse files
oschwaldclaude
andcommitted
Include the underlying cause in the FETCH_ERROR message
A FETCH_ERROR previously surfaced only "TypeError - fetch failed", with the real reason (DNS failure, refused connection, TLS error, etc.) hidden in the cause. Consumers that log only `code`/`error` never saw it. Append the underlying cause's message to the error string so the reason is visible without inspecting `cause`, which is still attached. STF-803 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c94db28 commit 717ed80

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ returned by the web API, we also return these `code` values:
166166
}
167167
```
168168

169+
For `FETCH_ERROR`, the `error` message includes the underlying failure reason
170+
(for example, a DNS or connection error) when one is available, and the
171+
original error is also attached as `cause`.
172+
169173
## Example
170174

171175
```js

src/webServiceClient.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,26 @@ describe('WebServiceClient', () => {
10891089
expect((err.cause as Error).message).toBe(error);
10901090
});
10911091

1092+
it('includes the underlying cause in the FETCH_ERROR message', async () => {
1093+
const fetchError = Object.assign(new TypeError('fetch failed'), {
1094+
cause: new Error('connect ECONNREFUSED 1.2.3.4:443'),
1095+
});
1096+
1097+
nockInstance
1098+
.post(fullPath('score'), score.request.basic)
1099+
.basicAuth(auth)
1100+
.replyWithError(fetchError);
1101+
1102+
const err = await expectError(client.score(transaction), {
1103+
code: 'FETCH_ERROR',
1104+
error: 'TypeError - fetch failed: connect ECONNREFUSED 1.2.3.4:443',
1105+
url: baseUrl + fullPath('score'),
1106+
cause: 'defined',
1107+
});
1108+
// The original error (with its own cause) is still attached.
1109+
expect((err.cause as Error).message).toBe('fetch failed');
1110+
});
1111+
10921112
test.each`
10931113
status | code | error
10941114
${400} | ${'IP_ADDRESS_INVALID'} | ${'ip address invalid'}

src/webServiceClient.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,15 @@ export default class WebServiceClient {
119119
{ cause: error }
120120
);
121121
}
122+
// Include the underlying cause's message in the error string so the
123+
// reason (e.g. a DNS or connection failure) is visible to consumers that
124+
// only log `code`/`error`, not just available via `cause`.
125+
const causeDetail =
126+
error.cause instanceof Error ? `: ${error.cause.message}` : '';
122127
throw new WebServiceError(
123128
{
124129
code: 'FETCH_ERROR',
125-
error: `${error.name} - ${error.message}`,
130+
error: `${error.name} - ${error.message}${causeDetail}`,
126131
url,
127132
},
128133
{ cause: error }

0 commit comments

Comments
 (0)