{"record":{"id":"35c423821df134ac","repo":"chatboxai/chatbox","slug":"vibedrop-authorization-failed","errorCode":null,"errorMessage":"VibeDrop authorization failed","messagePattern":"VibeDrop authorization failed","errorType":"http","errorClass":"VibedropAuthError","httpStatus":null,"severity":"error","filePath":"src/renderer/packages/vibedrop.ts","lineNumber":101,"sourceCode":"    ignoreResponseError: true,\n  })\n  return { status: response.status, json: response._data ?? null }\n}\n\nexport async function publishToVibedrop(params: PublishToVibedropParams): Promise<VibedropSite> {\n  const { html, vdKey, title, visibility, slug } = params\n  if (!html?.trim()) {\n    throw new Error('HTML content is empty, nothing to publish.')\n  }\n\n  const body: Record<string, unknown> = { html, visibility }\n  if (title) body.title = title\n  if (slug) body.slug = slug\n\n  const { status, json } = await postJson(`${VIBEDROP_API_ORIGIN}/v1/sites/inline`, body, vdKey)\n\n  if (status === 401 || status === 403) {\n    throw new VibedropAuthError(json?.error?.message || 'VibeDrop authorization failed')\n  }\n  if (status === 404 && json?.error?.code === 'slug_not_owned') {\n    throw new VibedropSlugNotOwnedError('slug no longer owned')\n  }\n  if (status >= 400 || !json?.site?.url) {\n    throw new Error(json?.error?.message || `Failed to publish to VibeDrop (status ${status})`)\n  }\n\n  return { slug: json.site.slug, url: json.site.url, visibility: json.site.visibility }\n}\n\n// ===== client-side caches (settings-persisted) =====\n\n// Decodes the email claim from the current account's JWT access token. Used to\n// bind the cached publish key to an account so it is never reused across\n// accounts (e.g. after switching login without an explicit logout).\nfunction currentAccountEmail(): string | null {\n  const token = authInfoStore.getState().accessToken","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/vibedrop.ts#L83-L119","documentation":"Thrown as VibedropAuthError when the VibeDrop inline-publish endpoint returns HTTP 401 or 403. It indicates the vdKey/bearer is missing, invalid, or expired. The message prefers the server's error.message and falls back to 'VibeDrop authorization failed'.","triggerScenarios":"postJson to /v1/sites/inline returns status 401 or 403; the catch `if (status === 401 || status === 403) throw new VibedropAuthError(json?.error?.message || 'VibeDrop authorization failed')` fires.","commonSituations":"Cached vdKey expired or was revoked; the user switched accounts and the cached key belongs to another account; the key was never issued (see email_required, error 193); clock skew or session invalidation server-side.","solutions":["Re-issue the vdKey by re-running the vibedrop key-issuance flow, then retry.","If the account changed, clear the cached key so a fresh one is issued for the current account.","Verify the Authorization header is being sent with the correct bearer value.","If the server message indicates a specific cause, follow it (e.g. re-login)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function hasVdKey(): boolean {\n  return !!getCachedVdKey()\n}\nif (!hasVdKey()) {\n  // run key-issuance flow before publishing\n}","typeGuard":"function isVibedropAuthError(e: unknown): e is VibedropAuthError {\n  return e instanceof VibedropAuthError\n}","tryCatchPattern":"try {\n  await publishToVibedrop(params)\n} catch (e) {\n  if (e instanceof VibedropAuthError) {\n    // clear cached vdKey, re-issue, then retry once\n  }\n}","preventionTips":["Clear the cached vdKey on account switch.","Re-issue keys when 401/403 is observed rather than looping.","Bind cached keys to the account email to avoid cross-account reuse."],"tags":["vibedrop","auth","publish","http"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}