From 897335b7013950d05d99c3b3d81760fa28f24398 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Mon, 12 Oct 2026 22:38:30 +0700 Subject: [PATCH] fix(studio): the refusal Immich gives is the one the upload dialog says --- docker/frontend/src/engine/immich.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docker/frontend/src/engine/immich.ts b/docker/frontend/src/engine/immich.ts index 526fc2a..e0c88c1 100644 --- a/docker/frontend/src/engine/immich.ts +++ b/docker/frontend/src/engine/immich.ts @@ -167,6 +167,26 @@ export async function forgetImmichServer(id: string): Promise { } } +// What to say when the upload was refused. The wrapper's own summary ("Immich +// upload failed") names nothing anyone can act on; Immich's answer underneath +// does — `{"message":"Missing required permission: asset.upload"}` is the error +// AND the fix, so it is what the dialog shows. The details are handed over as +// they came when they are not JSON, since a proxy's page is then the only clue +// there is. +function immichReason(body: { error?: string; details?: string }, status: number): string { + const details = (body.details ?? '').trim(); + if (details) { + try { + const message = (JSON.parse(details) as { message?: string }).message; + if (message) return String(message).slice(0, 300); + } catch { + /* not JSON — hand the text over as it stands */ + } + return details.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 300) || `HTTP ${status}`; + } + return body.error || `HTTP ${status}`; +} + // Upload an edited photo to Immich Cloud export async function uploadToImmich( bytes: Uint8Array, @@ -188,8 +208,8 @@ export async function uploadToImmich( body: bytes as BodyInit, }); if (!res.ok) { - const err = await res.json().catch(() => ({})); - return { ok: false, error: (err as any)?.error || (err as any)?.details || `HTTP ${res.status}` }; + const err = (await res.json().catch(() => ({}))) as { error?: string; details?: string }; + return { ok: false, error: immichReason(err, res.status) }; } const data = await res.json().catch(() => ({})); return { ok: true, id: (data as any)?.id };