From a01b5f5b78d5f42237fde3f94aa46f9a32376964 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 1 Oct 2026 16:16:57 +0200 Subject: [PATCH] The membership is read by its subject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The runtime asked the assignments stream's root for the last message by subject in the body, and the mesh grants a module's account only the subject-addressed form of the direct get — the server refused every read (Publish Violation on $JS.API.DIRECT.GET.ASSIGNMENTS for every module on the new runtime), so every runtime kept the derived shape. The address is now the stream then the subject, nothing in the body, which is the one address the account has. --- src/broker-nats.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/broker-nats.ts b/src/broker-nats.ts index 767f7d8..b6bf0d7 100644 --- a/src/broker-nats.ts +++ b/src/broker-nats.ts @@ -161,8 +161,11 @@ export async function connectNats( const subjectOfMine = node ? membershipSubject(node, self) : ""; if (subjectOfMine) { try { - const got = await conn.request(`$JS.API.DIRECT.GET.${ASSIGNMENTS_STREAM}`, - sc.encode(JSON.stringify({ last_by_subj: subjectOfMine })), { timeout: 5_000 }); + // The subject-addressed form of a direct get — the stream, then the subject, nothing in + // the body — because that is the one address the mesh grants this account on the + // stream's API; the body form asks the stream's root, which it may not. + const got = await conn.request(`$JS.API.DIRECT.GET.${ASSIGNMENTS_STREAM}.${subjectOfMine}`, + new Uint8Array(0), { timeout: 5_000 }); const status = got.headers?.code ?? 0; if (status === 0 && got.data.length > 0) { issued = JSON.parse(sc.decode(got.data)) as Membership; -- 2.54.0