gastownhall/beads · error

failed to update issue: %w

Error message

failed to update issue: %w

What it means

UpdateIssue failed at the HTTP layer when PUTting updates to an existing issue identified by IID. The cause is wrapped from doRequest.

Source

Thrown at internal/gitlab/client.go:369

	respBody, _, err := c.doRequest(ctx, http.MethodPost, urlStr, body)
	if err != nil {
		return nil, fmt.Errorf("failed to create issue: %w", err)
	}

	var issue Issue
	if err := json.Unmarshal(respBody, &issue); err != nil {
		return nil, fmt.Errorf("failed to parse create response: %w", err)
	}

	return &issue, nil
}

// UpdateIssue updates an existing issue in GitLab.
func (c *Client) UpdateIssue(ctx context.Context, iid int, updates map[string]interface{}) (*Issue, error) {
	urlStr := c.buildURL("/projects/"+c.projectPath()+"/issues/"+strconv.Itoa(iid), nil)
	respBody, _, err := c.doRequest(ctx, http.MethodPut, urlStr, updates)
	if err != nil {
		return nil, fmt.Errorf("failed to update issue: %w", err)
	}

	var issue Issue
	if err := json.Unmarshal(respBody, &issue); err != nil {
		return nil, fmt.Errorf("failed to parse update response: %w", err)
	}

	return &issue, nil
}

// GetIssueLinks retrieves issue links for the specified issue IID.
func (c *Client) GetIssueLinks(ctx context.Context, iid int) ([]IssueLink, error) {
	urlStr := c.buildURL("/projects/"+c.projectPath()+"/issues/"+strconv.Itoa(iid)+"/links", nil)
	respBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get issue links: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the IID exists in the configured project (FetchIssueByIID first)
  2. Check wrapped status: 404 → fix projectPath/iid, 403 → token scope, 400/422 → fix update keys/values
  3. Use valid state_event values ("close", "reopen") and correct label formats
  4. Check issue confidentiality/lock settings if 403 persists

Example fix

// before
client.UpdateIssue(ctx, 123, map[string]interface{}{"state": "closed"}) // invalid key
// after
client.UpdateIssue(ctx, 123, map[string]interface{}{"state_event": "close"})
Defensive patterns

Strategy: validation

Validate before calling

if iid <= 0 { return errors.New("invalid iid") }
if _, err := client.FetchIssueByIID(ctx, iid); err != nil {
	return fmt.Errorf("iid %d not found in configured project: %w", iid, err)
}

Type guard

func isUpdateRejected(err error) bool {
	return strings.Contains(err.Error(), "failed to update issue")
}

Try / catch

issue, err := client.UpdateIssue(ctx, iid, updates)
if err != nil {
	if strings.Contains(err.Error(), "404") { return fmt.Errorf("issue iid %d not found: %w", iid, err) }
	if strings.Contains(err.Error(), "403") { return fmt.Errorf("token lacks write access: %w", err) }
	return err
}

Prevention

When it happens

Trigger: PUT /projects/:id/issues/:iid fails: 404 (IID not found in the configured project or project path wrong), 400/422 invalid update keys or values, 401/403 token lacks write access, or network/context error.

Common situations: Passing an IID from a different project, sending update keys GitLab rejects (e.g. bad state_event, malformed labels), token without api scope, or updating a closed/locked issue without permission.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/c44bebc452d6cf3b. Report an issue: GitHub.