go-gitea/gitea · error

Failed to update issue title: ${resp.statusText}

Error message

Failed to update issue title: ${resp.statusText}

What it means

Thrown when saving an edited issue/PR title in the Gitea web UI. The submit handler POSTs the new title to the issue's update URL (data-update-url on the save button, resolving to POST /{owner}/{repo}/issues/{index}/title) and any non-2xx response aborts with the response's statusText, leaving the old title in place.

Source

Thrown at web_src/js/features/repo-issue.ts:410

  issueTitleEditor.querySelector('.ui.cancel.button')!.addEventListener('click', () => {
    hideElem(issueTitleEditor);
    hideElem('#pull-desc-editor');
    showElem(issueTitleDisplay);
    showElem('#pull-desc-display');
  });

  const pullDescEditor = document.querySelector('#pull-desc-editor'); // it may not exist for a merged PR
  const prTargetUpdateUrl = pullDescEditor?.getAttribute('data-target-update-url');

  const editSaveButton = issueTitleEditor.querySelector('.ui.primary.button')!;
  issueTitleEditor.addEventListener('submit', async (e) => {
    e.preventDefault();
    const newTitle = issueTitleInput.value.trim();
    try {
      if (newTitle && newTitle !== oldTitle) {
        const resp = await POST(editSaveButton.getAttribute('data-update-url')!, {data: new URLSearchParams({title: newTitle})});
        if (!resp.ok) {
          throw new Error(`Failed to update issue title: ${resp.statusText}`);
        }
      }
      if (prTargetUpdateUrl) {
        const newTargetBranch = document.querySelector('#pull-target-branch')!.getAttribute('data-branch');
        const oldTargetBranch = document.querySelector('#branch_target')!.textContent;
        if (newTargetBranch !== oldTargetBranch) {
          const resp = await POST(prTargetUpdateUrl, {data: new URLSearchParams({target_branch: String(newTargetBranch)})});
          if (!resp.ok) {
            throw new Error(`Failed to update PR target branch: ${resp.statusText}`);
          }
        }
      }
      ignoreAreYouSure(issueTitleEditor);
      window.location.reload();
    } catch (error) {
      console.error(error);
      showErrorToast(errorMessage(error));
    }

View on GitHub (pinned to 43ace7cc8a)

Solutions

  1. Confirm the new title is non-empty and actually different from the old one (the handler only sends it when newTitle && newTitle !== oldTitle, but server-side trimming can still reject whitespace-only titles)
  2. Reopen the issue page fresh and retry — this refreshes CSRF tokens and permissions
  3. Check the user still has write/push access to the repository
  4. If it persists, check the Gitea server log for the 500 root cause on the title-update route

Example fix

// before
const resp = await POST(editSaveButton.getAttribute('data-update-url')!, {data: new URLSearchParams({title: newTitle})});
if (!resp.ok) {
  throw new Error(`Failed to update issue title: ${resp.statusText}`);
}

// after (include status code and server message for diagnosis)
const resp = await POST(editSaveButton.getAttribute('data-update-url')!, {data: new URLSearchParams({title: newTitle})});
if (!resp.ok) {
  const body = await resp.json().catch(() => null);
  throw new Error(`Failed to update issue title: ${resp.status} ${body?.errorMessage ?? resp.statusText}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Skip the request entirely when there is nothing to change
const newTitle = issueTitleInput.value.trim();
if (!newTitle || newTitle === oldTitle) return;

Try / catch

try {
  if (newTitle && newTitle !== oldTitle) {
    const resp = await POST(editSaveButton.getAttribute('data-update-url')!, {data: new URLSearchParams({title: newTitle})});
    if (!resp.ok) throw new Error(`Failed to update issue title: ${resp.statusText}`);
  }
} catch (error) {
  console.error(error);
  showErrorToast(errorMessage(error)); // shipped pattern: toast, editor stays open, no data loss
}

Prevention

When it happens

Trigger: POST to the title-update endpoint returns non-ok: title is empty or whitespace after server-side trimming (400/422), user lost write permission to the repo or issue (403), the issue index no longer exists or was migrated (404), session/CSRF token expired so the request is rejected (403/419), or an internal error occurred while saving (500).

Common situations: Editing a title in one tab while the issue was closed/locked/migrated in another; permissions changed (user demoted from collaborator) while the edit dialog was open; long-idle tab with a stale CSRF token; concurrent edit where the title was already changed by someone else.

Related errors


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