Skip to content

Commit e1ef298

Browse files
authored
backport 8750 (add documentation_url to error messages) (#8751)
* add documentation_url * changeset * fix nested indenting
1 parent 04ba075 commit e1ef298

File tree

4 files changed

+119
-9
lines changed

4 files changed

+119
-9
lines changed

.changeset/lovely-lemons-count.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
fix: include documentation_url in API Errors if provided

packages/wrangler/src/__tests__/cfetch-utils.test.ts

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,30 @@ describe("throwFetchError", () => {
4747
mockAccountId();
4848
mockApiToken();
4949
runInTempDir();
50-
mockConsoleMethods();
50+
const std = mockConsoleMethods();
5151

52-
it("should include api errors and messages in error", async () => {
52+
it("should include api errors, messages and documentation_url in error", async () => {
5353
msw.use(
5454
http.get("*/user", () => {
5555
return HttpResponse.json(
5656
createFetchResult(
5757
null,
5858
false,
5959
[
60-
{ code: 10001, message: "error one" },
61-
{ code: 10002, message: "error two" },
60+
{
61+
code: 10001,
62+
message: "error one",
63+
documentation_url: "https://example.com/1",
64+
},
65+
{
66+
code: 10002,
67+
message: "error two",
68+
documentation_url: "https://example.com/2",
69+
},
70+
{
71+
code: 10003,
72+
message: "error three",
73+
},
6274
],
6375
["message one", "message two"]
6476
)
@@ -68,8 +80,15 @@ describe("throwFetchError", () => {
6880
await expect(runWrangler("whoami")).rejects.toMatchObject({
6981
text: "A request to the Cloudflare API (/user) failed.",
7082
notes: [
71-
{ text: "error one [code: 10001]" },
72-
{ text: "error two [code: 10002]" },
83+
{
84+
text: "error one [code: 10001]\nTo learn more about this error, visit: https://example.com/1",
85+
},
86+
{
87+
text: "error two [code: 10002]\nTo learn more about this error, visit: https://example.com/2",
88+
},
89+
{
90+
text: "error three [code: 10003]",
91+
},
7392
{ text: "message one" },
7493
{ text: "message two" },
7594
{
@@ -79,19 +98,100 @@ describe("throwFetchError", () => {
7998
});
8099
});
81100

101+
it("nested", async () => {
102+
msw.use(
103+
http.get("*/user", () => {
104+
return HttpResponse.json(
105+
createFetchResult(
106+
null,
107+
false,
108+
[
109+
{
110+
code: 10001,
111+
message: "error one",
112+
documentation_url: "https://example.com/1",
113+
error_chain: [
114+
{
115+
code: 10002,
116+
message: "error two",
117+
error_chain: [
118+
{
119+
code: 10003,
120+
message: "error three",
121+
documentation_url: "https://example.com/3",
122+
error_chain: [
123+
{
124+
code: 10004,
125+
message: "error 4",
126+
documentation_url: "https://example.com/4",
127+
},
128+
],
129+
},
130+
],
131+
},
132+
],
133+
},
134+
],
135+
["message one", "message two"]
136+
)
137+
);
138+
})
139+
);
140+
await expect(runWrangler("whoami")).rejects.toMatchInlineSnapshot(
141+
`[APIError: A request to the Cloudflare API (/user) failed.]`
142+
);
143+
144+
expect(std.out).toMatchInlineSnapshot(`
145+
"Getting User settings...
146+
147+
X [ERROR] A request to the Cloudflare API (/user) failed.
148+
149+
error one [code: 10001]
150+
To learn more about this error, visit: https://example.com/1
151+
152+
- error two [code: 10002]
153+
154+
- error three [code: 10003]
155+
To learn more about this error, visit: https://example.com/3
156+
157+
- error 4 [code: 10004]
158+
To learn more about this error, visit: https://example.com/4
159+
160+
message one
161+
message two
162+
163+
If you think this is a bug, please open an issue at:
164+
https://github.com/cloudflare/workers-sdk/issues/new/choose
165+
166+
"
167+
`);
168+
});
169+
82170
it("should include api errors without messages", async () => {
83171
msw.use(
84172
http.get("*/user", () => {
85173
return HttpResponse.json({
86174
result: null,
87175
success: false,
88-
errors: [{ code: 10000, message: "error" }],
176+
errors: [
177+
{
178+
code: 10000,
179+
message: "error",
180+
documentation_url: "https://example.com/1",
181+
},
182+
{ code: 10001, message: "error 1" },
183+
],
89184
});
90185
})
91186
);
92187
await expect(runWrangler("whoami")).rejects.toMatchObject({
93188
text: "A request to the Cloudflare API (/user) failed.",
94-
notes: [{ text: "error [code: 10000]" }],
189+
notes: [
190+
{
191+
text: "error [code: 10000]\nTo learn more about this error, visit: https://example.com/1",
192+
},
193+
{ text: "error 1 [code: 10001]" },
194+
],
95195
});
96196
});
97197
});

packages/wrangler/src/cfetch/errors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ParseError } from "../parse";
22

33
export interface FetchError {
44
code: number;
5+
documentation_url?: string;
56
message: string;
67
error_chain?: FetchError[];
78
}

packages/wrangler/src/cfetch/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,19 @@ function hasCursor(result_info: unknown): result_info is { cursor: string } {
198198
}
199199

200200
function renderError(err: FetchError, level = 0): string {
201+
const indent = " ".repeat(level);
201202
const chainedMessages =
202203
err.error_chain
203204
?.map(
204205
(chainedError) =>
205-
`\n${" ".repeat(level)}- ${renderError(chainedError, level + 1)}`
206+
`\n\n${indent}- ${renderError(chainedError, level + 1)}`
206207
)
207208
.join("\n") ?? "";
208209
return (
209210
(err.code ? `${err.message} [code: ${err.code}]` : err.message) +
211+
(err.documentation_url
212+
? `\n${indent}To learn more about this error, visit: ${err.documentation_url}`
213+
: "") +
210214
chainedMessages
211215
);
212216
}

0 commit comments

Comments
 (0)