From d77f428441f28510c77c23cbf4c075c97b0caef0 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 15 May 2026 08:22:41 +0800 Subject: [PATCH] fix(tlon): wrap malformed scry json --- CHANGELOG.md | 1 + extensions/tlon/src/urbit/channel-ops.test.ts | 36 +++++++++++++++++++ extensions/tlon/src/urbit/channel-ops.ts | 6 +++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 extensions/tlon/src/urbit/channel-ops.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b057208d1e..fc389127da6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,6 +97,7 @@ Docs: https://docs.openclaw.ai - Signal: return a stable installer error when GitHub release metadata is malformed JSON. - ClawHub: report malformed successful marketplace JSON responses with owned errors instead of leaking raw parser failures. - Provider usage: report malformed successful usage JSON responses with stable provider errors instead of leaking raw parser failures. +- Tlon/Urbit: report malformed scry response JSON with owned errors instead of leaking raw parser failures. - Matrix: ignore malformed percent-encoding in optional location URI parameters instead of letting a bad `geo:` event abort inbound message handling. - Web search: auto-detect Brave through its legacy `tools.web.search.apiKey` compatibility fallback while keeping doctor migration to `plugins.entries.brave.config.webSearch.apiKey` as the canonical repair, so allowlisted isolated cron runs do not report `web_search` unavailable before migration. Fixes #81538. Thanks @atomicmonk. - Plugins: memoize repeated in-process plugin metadata snapshots and keep vanished managed-install residue from forcing full derived discovery, reducing gateway/status startup scans under large plugin sets. Fixes #81143 and #79806. (#81570) Thanks @Kaspre, @holgergruenhagen, @JanPlessow, and @mjamiv. diff --git a/extensions/tlon/src/urbit/channel-ops.test.ts b/extensions/tlon/src/urbit/channel-ops.test.ts new file mode 100644 index 00000000000..ab3d4e45638 --- /dev/null +++ b/extensions/tlon/src/urbit/channel-ops.test.ts @@ -0,0 +1,36 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { scryUrbitPath } from "./channel-ops.js"; +import { urbitFetch } from "./fetch.js"; + +vi.mock("./fetch.js", () => ({ + urbitFetch: vi.fn(), +})); + +describe("Urbit channel operations", () => { + beforeEach(() => { + vi.mocked(urbitFetch).mockReset(); + }); + + it("wraps malformed scry response JSON", async () => { + const release = vi.fn().mockResolvedValue(undefined); + vi.mocked(urbitFetch).mockResolvedValue({ + response: new Response("{not json", { + status: 200, + headers: { "content-type": "application/json" }, + }), + finalUrl: "https://example.com/~/scry/chat/inbox.json", + release, + }); + + await expect( + scryUrbitPath( + { + baseUrl: "https://example.com", + cookie: "urbauth-~zod=123", + }, + { path: "/chat/inbox.json", auditContext: "test" }, + ), + ).rejects.toThrow("Urbit scry response was malformed JSON for path /chat/inbox.json"); + expect(release).toHaveBeenCalledTimes(1); + }); +}); diff --git a/extensions/tlon/src/urbit/channel-ops.ts b/extensions/tlon/src/urbit/channel-ops.ts index b18324c7660..0bce546a053 100644 --- a/extensions/tlon/src/urbit/channel-ops.ts +++ b/extensions/tlon/src/urbit/channel-ops.ts @@ -88,7 +88,11 @@ export async function scryUrbitPath( if (!response.ok) { throw new Error(`Scry failed: ${response.status} for path ${params.path}`); } - return await response.json(); + try { + return await response.json(); + } catch (cause) { + throw new Error(`Urbit scry response was malformed JSON for path ${params.path}`, { cause }); + } } finally { await release(); }