Skip to content

Commit 958d236

Browse files
committed
Handle Bun invalid URL errors
Treat Bun's ERR_INVALID_URL TypeErrors the same way as the Invalid URL messages produced by Deno and Node when classifying malformed ActivityPub IRI fields. This keeps live inbox handling and queued inbox workers from retrying permanently malformed payloads only on Bun. Add a small regression test for the shared invalid URL TypeError helper so future runtime message differences stay covered.
1 parent c2b5e63 commit 958d236

4 files changed

Lines changed: 34 additions & 10 deletions

File tree

packages/fedify/src/federation/handler.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
hasSignature,
1717
InvalidContextReferenceError,
1818
isClearlyMalformedContextReference,
19+
isInvalidUrlTypeError,
1920
verifyCompactJsonLd,
2021
wrapContextLoaderForJsonLd,
2122
} from "../sig/ld.ts";
@@ -101,8 +102,9 @@ function isInvalidJsonLdError(error: unknown): error is Error {
101102

102103
function isValidationTypeError(error: unknown): error is TypeError {
103104
return error instanceof TypeError &&
104-
/^(Invalid JSON-LD:|Invalid type:|Unexpected type:|Invalid URL)/
105-
.test(error.message);
105+
(/^(Invalid JSON-LD:|Invalid type:|Unexpected type:)/
106+
.test(error.message) ||
107+
isInvalidUrlTypeError(error));
106108
}
107109

108110
function isPermanentActivityParseError(error: unknown): error is Error {
@@ -115,8 +117,8 @@ function isPermanentActivityParseError(error: unknown): error is Error {
115117
// bucket. jsonld.SyntaxError is similarly only permanent when it is local
116118
// to the payload rather than a remote-context loading failure. Raw loader
117119
// TypeErrors for @context resolution are normalized earlier at the
118-
// context-loading layer, so any remaining "Invalid URL ..." here comes from
119-
// sender-controlled ActivityPub IRI fields and stays permanent.
120+
// context-loading layer, so any remaining invalid-URL TypeError here comes
121+
// from sender-controlled ActivityPub IRI fields and stays permanent.
120122
return isInvalidJsonLdError(error) || isValidationTypeError(error);
121123
}
122124

packages/fedify/src/federation/middleware.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
hasSignature,
4747
InvalidContextReferenceError,
4848
isClearlyMalformedContextReference,
49+
isInvalidUrlTypeError,
4950
signJsonLd,
5051
wrapContextLoaderForJsonLd,
5152
} from "../sig/ld.ts";
@@ -157,8 +158,8 @@ function isPermanentInboxParseError(error: unknown): error is Error {
157158
// metadata URL failures. jsonld.SyntaxError is similarly only permanent
158159
// when it is local to the payload rather than a remote-context loading
159160
// failure. Raw loader TypeErrors for @context resolution are normalized
160-
// earlier at the context-loading layer, so any remaining "Invalid URL ..."
161-
// here comes from sender-controlled ActivityPub IRI fields and stays
161+
// earlier at the context-loading layer, so any remaining invalid-URL
162+
// TypeError here comes from sender-controlled ActivityPub IRI fields and stays
162163
// permanent instead of churning the retry queue.
163164
return (error instanceof Error &&
164165
(error.name === "UnsafeJsonLdError" ||
@@ -167,8 +168,9 @@ function isPermanentInboxParseError(error: unknown): error is Error {
167168
(error.name === "jsonld.SyntaxError" &&
168169
!isRemoteContextLoadingFailure(error)))) ||
169170
(error instanceof TypeError &&
170-
/^(Invalid JSON-LD:|Invalid type:|Unexpected type:|Invalid URL)/
171-
.test(error.message));
171+
(/^(Invalid JSON-LD:|Invalid type:|Unexpected type:)/
172+
.test(error.message) ||
173+
isInvalidUrlTypeError(error)));
172174
}
173175

174176
/**

packages/fedify/src/sig/ld.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,29 @@ import {
2121
compactJsonLd,
2222
createSignature,
2323
detachSignature,
24+
isInvalidUrlTypeError,
2425
type Signature,
2526
signJsonLd,
2627
UnsafeJsonLdError,
2728
verifyJsonLd,
2829
verifySignature,
2930
} from "./ld.ts";
3031

32+
test("isInvalidUrlTypeError()", () => {
33+
assert(isInvalidUrlTypeError(new TypeError("Invalid URL: http://[")));
34+
assert(
35+
isInvalidUrlTypeError(
36+
new TypeError('"http://[" cannot be parsed as a URL.'),
37+
),
38+
);
39+
const error = new TypeError("Failed to parse URL") as TypeError & {
40+
code?: string;
41+
};
42+
error.code = "ERR_INVALID_URL";
43+
assert(isInvalidUrlTypeError(error));
44+
assertFalse(isInvalidUrlTypeError(new TypeError("Failed to fetch")));
45+
});
46+
3147
test("attachSignature()", () => {
3248
const sig: Signature = {
3349
"@context": "https://w3id.org/identity/v1",

packages/fedify/src/sig/ld.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,13 @@ function normalizeContextReference(
392392
return URL.canParse(reference) ? new URL(reference).href : reference;
393393
}
394394

395-
function isInvalidUrlTypeError(error: unknown): error is TypeError {
395+
/** @internal */
396+
export function isInvalidUrlTypeError(error: unknown): error is TypeError {
397+
const code = (error as { code?: unknown }).code;
396398
return error instanceof TypeError &&
397-
/^Invalid URL(?::|$)/.test(error.message);
399+
(code === "ERR_INVALID_URL" ||
400+
/^Invalid URL(?::|$)/.test(error.message) ||
401+
/ cannot be parsed as a URL\.?$/.test(error.message));
398402
}
399403

400404
async function applyGraphAliasContext(

0 commit comments

Comments
 (0)