BigPizzaV3/CodexPlusPlus · error · Error

分享不存在、已撤销或已过期。

Error message

分享不存在、已撤销或已过期。

What it means

After fetching /api/shares/:id, showShare() checks response.ok; any non-2xx (404, 410, etc.) is converted into this single user-facing error. The server rejects the share because it does not exist, was revoked by its owner, or has passed its expiry time, and the client collapses all these cases into one message for privacy (not revealing which).

Solutions

  1. Confirm the URL id segment matches the original share link exactly (no truncation by copy/paste).
  2. Request a fresh share link from the author — if it expired or was revoked only a new link will work.
  3. Check you are on the same site/deployment the share was created on; shares are not cross-host.
  4. If you are the operator, inspect the /api/shares/:id handler logs to distinguish 404 vs 410 vs 403.

Example fix

// before
if (!response.ok) throw new Error("分享不存在、已撤销或已过期。");
// after
if (response.status === 410) throw new Error("该分享已过期,请向分享者索取新链接。");
if (!response.ok) throw new Error("分享不存在、已撤销或已过期。");
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(`/api/shares/${id}`, { cache: "no-store" });
if (res.status === 404 || res.status === 410) {
  viewNotice.textContent = "该分享已失效,请索取新的分享链接。";
  return;
}

Try / catch

try {
  await showShare(id);
} catch (e) {
  if (e.message === "分享不存在、已撤销或已过期。") {
    viewNotice.textContent = "分享链接已失效或已过期,请联系分享者重新生成。";
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling showShare with an id whose share record returns 404/410 from GET /api/shares/:id, with cache:"no-store" so a fresh authoritative response is always required.

Common situations: Opening a link after the share expired (TTL elapsed), after the author revoked it, with a mistyped/truncated id, or against the wrong backend/deployment where the share was never created.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/03f1e0a89d4b900e. Report an issue: GitHub.

Appendix: source

Thrown at services/share-site/app.js:100

    setNotice("分享已撤销。", "success");
  });
}

async function showShare(id) {
  createView.hidden = true;
  viewer.hidden = false;
  const viewContent = document.querySelector("[data-view-content]");
  const viewMeta = document.querySelector("[data-view-meta]");
  const viewNotice = document.querySelector("[data-view-notice]");
  const importButton = document.querySelector("[data-import-session]");

  try {
    const keyValue = new URLSearchParams(location.hash.slice(1)).get("k");
    if (!keyValue) throw new Error("链接缺少解密密钥。请使用完整的分享链接。");

    const response = await fetch(`/api/shares/${id}`, { cache: "no-store" });
    const data = await response.json();
    if (!response.ok) throw new Error("分享不存在、已撤销或已过期。");

    const plaintext = await decryptText(data.encrypted, keyValue);
    try {
      const parsed = JSON.parse(plaintext);
      if (parsed?.kind === "codex-rollout" && typeof parsed.content === "string") {
        sharedSession = parsed;
        viewContent.textContent = rolloutToMarkdown(parsed.content, parsed.title);
        importButton.hidden = false;
        importButton.addEventListener("click", importSharedSession, { once: true });
      } else if (parsed?.kind === "codex-session" && Array.isArray(parsed.messages)) {
        sharedSession = parsed;
        viewContent.textContent = sessionToMarkdown(parsed);
        importButton.hidden = false;
        importButton.addEventListener("click", importSharedSession, { once: true });
      } else {
        viewContent.textContent = plaintext;
      }
    } catch {

View on GitHub (pinned to b1ed92e5e4)