sigoden/dufs · error · Error

Failed to fetch token

Error message

Failed to fetch token

What it means

This is a browser-side error thrown by setupDownloadWithToken in dufs's bundled index.js. Before following a download link, the page fetches a one-time token from the link's URL (with tokengen param); if the token request returns a non-2xx response, it throws 'Failed to fetch token' instead of navigating the download, so a stale/invalid token never reaches the actual download URL.

Solutions

  1. Refresh the page to re-establish session/auth state, then retry the download
  2. Re-login or pass correct credentials so the tokengen endpoint returns 200
  3. Verify the file still exists at the link's href on the server
  4. Check dufs --auth rules allow the current user to access the path
  5. Check server logs / network tab for the tokengen request's actual status code

Example fix

// before
const res = await fetch(tokengenUrl);
if (!res.ok) throw new Error("Failed to fetch token");
// after
const res = await fetch(tokengenUrl, { credentials: "same-origin" });
if (!res.ok) {
  if (res.status === 401) { location.href = "/@login?next=" + encodeURIComponent(location.href); return; }
  throw new Error(`Failed to fetch token: HTTP ${res.status}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const u = new URL(link.getAttribute("href"));
u.searchParams.set("tokengen", "");
if (!u) throw new Error("download link has no href");

Try / catch

try {
  await setupDownloadWithToken(e);
} catch (err) {
  if (String(err.message).includes("Failed to fetch token")) {
    alert("Session expired — please refresh the page and log in again.");
    location.reload();
  } else { throw err; }
}

Prevention

When it happens

Trigger: User clicks a download link whose href points at a resource requiring auth, but the tokengen fetch (fetch(tokengenUrl)) responds with res.ok === false — e.g. 401 because the session/token cookies expired, 403 because the user lost write permission, or 404 because the target file was deleted or moved before the click.

Common situations: Session expired while the index page stayed open; server restarted and in-memory auth state changed; the file was renamed/removed between page render and click; a proxy stripped the tokengen query param; misconfigured auth rules (--auth) denying the user access to that path.

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 sigoden/dufs@fe7fd564f8 (2026-09-09). Data as JSON: /api/errors/f2dc5a4308552097. Report an issue: GitHub.

Appendix: source

Thrown at assets/index.js:567

      try {
        await checkAuth("login");
      } catch { }
      location.reload();
    });
  }
}

function setupDownloadWithToken() {
  document.querySelectorAll("a.dlwt").forEach(link => {
    link.addEventListener("click", async e => {
      e.preventDefault();
      try {
        const link = e.currentTarget || e.target;
        const originalHref = link.getAttribute("href");
        const tokengenUrl = new URL(originalHref);
        tokengenUrl.searchParams.set("tokengen", "");
        const res = await fetch(tokengenUrl);
        if (!res.ok) throw new Error("Failed to fetch token");
        const token = await res.text();
        const downloadUrl = new URL(originalHref);
        downloadUrl.searchParams.set("token", token);
        const tempA = document.createElement("a");
        tempA.href = downloadUrl.toString();
        tempA.download = "";
        document.body.appendChild(tempA);
        tempA.click();
        document.body.removeChild(tempA);
      } catch (err) {
        alert(`Failed to download, ${err.message}`);
      }
    });
  });
}

function setupSearch() {
  const $searchbar = document.querySelector(".searchbar");

View on GitHub (pinned to fe7fd564f8)