Skip to content

Commit c348c48

Browse files
committed
fix: harden discord media fallback regressions (#28906) (thanks @Sid-Qin)
1 parent ce6910e commit c348c48

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ Docs: https://docs.openclaw.ai
110110

111111
### Fixes
112112

113+
- Discord/Inbound media fallback: preserve attachment and sticker metadata when Discord CDN fetch/save fails by keeping URL-based media entries in context, with regression coverage for save failures and mixed success/failure ordering. Landed from contributor PR #28906 by @Sid-Qin. Thanks @Sid-Qin.
113114
- Docs/Docker images: clarify the official GHCR image source and tag guidance (`main`, `latest`, `<version>`), and document that `OPENCLAW_IMAGE` skips local image builds but still uses the repo-local compose/setup flow. (#27214, #31180) Fixes #15655. Thanks @ipl31.
114115
- Agents/Model fallback: classify additional network transport errors (`ECONNREFUSED`, `ENETUNREACH`, `EHOSTUNREACH`, `ENETRESET`, `EAI_AGAIN`) as failover-worthy so fallback chains advance when primary providers are unreachable. Landed from contributor PR #19077 by @ayanesakura. Thanks @ayanesakura.
115116
- Agents/Copilot token refresh: refresh GitHub Copilot runtime API tokens after auth-expiry failures and re-run with the renewed token so long-running embedded/subagent turns do not fail on mid-session 401 expiry. Landed from contributor PR #8805 by @Arthur742Ramos. Thanks @Arthur742Ramos.

src/discord/monitor/message-utils.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,83 @@ describe("resolveMediaList", () => {
334334
]);
335335
});
336336

337+
it("falls back to URL when saveMediaBuffer fails", async () => {
338+
const attachment = {
339+
id: "att-save-fail",
340+
url: "https://cdn.discordapp.com/attachments/1/photo.png",
341+
filename: "photo.png",
342+
content_type: "image/png",
343+
};
344+
fetchRemoteMedia.mockResolvedValueOnce({
345+
buffer: Buffer.from("image"),
346+
contentType: "image/png",
347+
});
348+
saveMediaBuffer.mockRejectedValueOnce(new Error("disk full"));
349+
350+
const result = await resolveMediaList(
351+
asMessage({
352+
attachments: [attachment],
353+
}),
354+
512,
355+
);
356+
357+
expect(fetchRemoteMedia).toHaveBeenCalledTimes(1);
358+
expect(saveMediaBuffer).toHaveBeenCalledTimes(1);
359+
expect(result).toEqual([
360+
{
361+
path: attachment.url,
362+
contentType: "image/png",
363+
placeholder: "<media:image>",
364+
},
365+
]);
366+
});
367+
368+
it("preserves downloaded attachments alongside failed ones", async () => {
369+
const goodAttachment = {
370+
id: "att-good",
371+
url: "https://cdn.discordapp.com/attachments/1/good.png",
372+
filename: "good.png",
373+
content_type: "image/png",
374+
};
375+
const badAttachment = {
376+
id: "att-bad",
377+
url: "https://cdn.discordapp.com/attachments/1/bad.pdf",
378+
filename: "bad.pdf",
379+
content_type: "application/pdf",
380+
};
381+
382+
fetchRemoteMedia
383+
.mockResolvedValueOnce({
384+
buffer: Buffer.from("image"),
385+
contentType: "image/png",
386+
})
387+
.mockRejectedValueOnce(new Error("network timeout"));
388+
saveMediaBuffer.mockResolvedValueOnce({
389+
path: "/tmp/good.png",
390+
contentType: "image/png",
391+
});
392+
393+
const result = await resolveMediaList(
394+
asMessage({
395+
attachments: [goodAttachment, badAttachment],
396+
}),
397+
512,
398+
);
399+
400+
expect(result).toEqual([
401+
{
402+
path: "/tmp/good.png",
403+
contentType: "image/png",
404+
placeholder: "<media:image>",
405+
},
406+
{
407+
path: badAttachment.url,
408+
contentType: "application/pdf",
409+
placeholder: "<media:document>",
410+
},
411+
]);
412+
});
413+
337414
it("keeps sticker metadata when sticker download fails", async () => {
338415
const sticker = {
339416
id: "sticker-fallback",

0 commit comments

Comments
 (0)