go-gitea/gitea · warning

Failed to reload page: ${resp.statusText}

Error message

Failed to reload page: ${resp.statusText}

What it means

Thrown by the issue sidebar combo-list component after the user changes a sidebar value (labels, milestone, assignees, etc.). To reflect the change it re-fetches the current page with GET(window.location.href) and re-parses it; any non-2xx response aborts the partial refresh so the sidebar would otherwise show stale data.

Source

Thrown at web_src/js/features/repo-issue-sidebar-combolist.ts:88

  updateUiList(changedValues: Array<string>) {
    if (!this.elList) return;
    const elEmptyTip = this.elList.querySelector(':scope > .item.empty-list')!;
    queryElemChildren(this.elList, '.item:not(.empty-list)', (el) => el.remove());
    for (const value of changedValues) {
      const el = this.elDropdown.querySelector<HTMLElement>(`.menu > .item[data-value="${CSS.escape(value)}"]`);
      if (!el) continue;
      const listItem = el.cloneNode(true) as HTMLElement;
      queryElems(listItem, '.item-check-mark, .item-secondary-info', (el) => el.remove());
      this.elList.append(listItem);
    }
    const hasItems = Boolean(this.elList.querySelector('.item:not(.empty-list)'));
    toggleElem(elEmptyTip, !hasItems);
  }

  async reloadPagePartially() {
    const resp = await GET(window.location.href);
    if (!resp.ok) throw new Error(`Failed to reload page: ${resp.statusText}`);
    const doc = parseDom(await resp.text(), 'text/html');

    // we can safely replace the whole right part (sidebar) because there are only some dropdowns and lists
    const newSidebar = doc.querySelector('.issue-content-right')!;
    this.elIssueSidebar.replaceWith(newSidebar);

    // for the main content (left side), at the moment we only support handling known timeline items
    const newMainContent = doc.querySelector('.issue-content-left')!;
    syncIssueMainContentTimelineItems(this.elIssueMainContent, newMainContent);
  }

  async sendRequestToBackend(changedValues: Array<string>): Promise<Response | null> {
    let lastResp: Response | null = null;
    if (this.updateAlgo === 'diff') {
      for (const value of this.initialValues) {
        if (!changedValues.includes(value)) {
          lastResp = await POST(this.updateUrl, {data: new URLSearchParams({action: 'detach', id: value})});
          if (!lastResp.ok) return lastResp;

View on GitHub (pinned to 43ace7cc8a)

Solutions

  1. Reload the full page (F5) — this re-authenticates and rebuilds the sidebar; the sidebar change itself usually already applied via sendRequestToBackend
  2. Log in again if the session expired, then retry the sidebar action
  3. Verify the issue URL still resolves (repo not renamed/transfered/private)
  4. If 500/502, check server and proxy logs for the failing page render

Example fix

// before
const resp = await GET(window.location.href);
if (!resp.ok) throw new Error(`Failed to reload page: ${resp.statusText}`);

// after (fall back to a full page reload instead of just erroring)
const resp = await GET(window.location.href);
if (!resp.ok) {
  if (resp.redirected || resp.status === 401 || resp.status === 403) window.location.reload();
  else throw new Error(`Failed to reload page: ${resp.status} ${resp.statusText}`);
}
Defensive patterns

Strategy: fallback

Validate before calling

// Verify the page is still reachable and the response is the same document before swapping
const resp = await GET(window.location.href, {headers: {'X-No-Redirect': '1'}});
if (!resp.ok || resp.redirected) throw new Error(`Failed to reload page: ${resp.status}`);

Type guard

const isIssueDocument = (doc: Document): boolean =>
  !!doc.querySelector('.issue-content-right') && !!doc.querySelector('.issue-content-left');

Try / catch

try {
  await comboList.reloadPagePartially();
} catch {
  // fallback: the sidebar request already succeeded; a full reload re-syncs the UI
  window.location.reload();
}

Prevention

When it happens

Trigger: GET of the current issue URL returns non-ok: session expired and the anonymous request got a redirect-to-login that fails resp.ok handling or a 403 for a private repo, the issue was deleted or the repo made private/transfered while open (404), or the server/proxy errored (500/502).

Common situations: Long-lived tab whose session cookie expired before a sidebar edit was saved; issue moved by migration or repo transfer; SSO/proxy in front of Gitea rejecting the re-fetch; server restart mid-session.

Related errors


AI-assisted analysis of go-gitea/gitea@43ace7cc8a (2026-08-15). Data as JSON: /api/errors/b95ce7257c610260. Report an issue: GitHub.