diff --git a/src/cli/commands/inbox.remote.ts b/src/cli/commands/inbox.remote.ts index 2d06c2d6..0de69f94 100644 --- a/src/cli/commands/inbox.remote.ts +++ b/src/cli/commands/inbox.remote.ts @@ -907,7 +907,10 @@ export function registerInboxCommands(program: Command, output: (data: unknown, try { const ds = resolveMailDataSource(); const msg = opts.download ? await ds.getMessage(emailId) : await requireMessage(ds, emailId); - if (!msg || (opts.download && msg.id !== emailId)) { + if (!msg) { + throw new Error("attachment message not found in the active inbox store"); + } + if (opts.download && msg.id !== emailId) { throw new Error("attachment download requires the exact full message id"); } const fullId = msg.id; diff --git a/src/cli/commands/inbox.test.ts b/src/cli/commands/inbox.test.ts index cd4ab560..d1d3f853 100644 --- a/src/cli/commands/inbox.test.ts +++ b/src/cli/commands/inbox.test.ts @@ -1234,6 +1234,35 @@ describe("inbox attachments", () => { // ─── inbox attachment ──────────────────────────────────────────────────────── describe("inbox attachment", () => { + it("reports an exact full message id missing from the active store as not found", async () => { + const id = crypto.randomUUID(); + const dir = mkdtempSync(join(tmpdir(), "emails-cli-missing-attachment-")); + try { + const failed = await runInboxSubprocessExpectingExit([ + "--json", + "inbox", + "attachment", + id, + "--download", + "--index", + "0", + "--output-dir", + dir, + ]); + + expect(failed.exitCode).toBe(1); + expect(failed.stdout).toBe(""); + const payload = JSON.parse(failed.stderr) as { + error: { code: string; message: string }; + }; + expect(payload.error.code).toBe("not_found"); + expect(payload.error.message).toBe("attachment message not found in the active inbox store"); + expect(readdirSync(dir)).toEqual([]); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + it("lists attachment metadata (no local paths in self-hosted mode)", async () => { const email = seedEmail({ subject: "Has attachments",