{"record":{"id":"e85fc11d5d57d9fc","repo":"gastownhall/beads","slug":"failed-to-parse-update-response-w-e85fc1","errorCode":null,"errorMessage":"failed to parse update response: %w","messagePattern":"failed to parse update response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":374,"sourceCode":"\tvar issue Issue\n\tif err := json.Unmarshal(respBody, &issue); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse create response: %w\", err)\n\t}\n\n\treturn &issue, nil\n}\n\n// UpdateIssue updates an existing issue in GitLab.\nfunc (c *Client) UpdateIssue(ctx context.Context, iid int, updates map[string]interface{}) (*Issue, error) {\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/issues/\"+strconv.Itoa(iid), nil)\n\trespBody, _, err := c.doRequest(ctx, http.MethodPut, urlStr, updates)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to update issue: %w\", err)\n\t}\n\n\tvar issue Issue\n\tif err := json.Unmarshal(respBody, &issue); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse update response: %w\", err)\n\t}\n\n\treturn &issue, nil\n}\n\n// GetIssueLinks retrieves issue links for the specified issue IID.\nfunc (c *Client) GetIssueLinks(ctx context.Context, iid int) ([]IssueLink, error) {\n\turlStr := c.buildURL(\"/projects/\"+c.projectPath()+\"/issues/\"+strconv.Itoa(iid)+\"/links\", nil)\n\trespBody, _, err := c.doRequest(ctx, http.MethodGet, urlStr, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get issue links: %w\", err)\n\t}\n\n\tvar links []IssueLink\n\tif err := json.Unmarshal(respBody, &links); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse issue links response: %w\", err)\n\t}\n","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L356-L392","documentation":"UpdateIssue received a response body that could not be decoded into a single Issue object after a successful PUT. The body was HTML, an error envelope, or incompatible with the Issue struct.","triggerScenarios":"PUT /projects/:id/issues/:iid returns a non-issue JSON payload (proxy error envelope, GitLab schema drift, or an interceptor returning unexpected JSON) so json.Unmarshal into Issue fails.","commonSituations":"SSO middleware rewriting API responses, GitLab version mismatch with the library's Issue struct, or a service mesh returning JSON errors with 2xx status.","solutions":["Log the raw response body and wrapped Unmarshal error to find the mismatching field","Update the library/Issue struct to match the GitLab server version","Bypass or fix proxies/middleware that rewrite API responses","Test the same PUT with curl to confirm the expected issue JSON is returned"],"exampleFix":"// before\n_, err := client.UpdateIssue(ctx, iid, updates)\n// after\nissue, err := client.UpdateIssue(ctx, iid, updates)\nif err != nil { return fmt.Errorf(\"update iid %d failed: %w\", iid, err) }","handlingStrategy":"try-catch","validationCode":"req, _ := http.NewRequest(http.MethodPut, url, body)\nresp, _ := http.DefaultClient.Do(req)\nct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"application/json\") { return fmt.Errorf(\"non-JSON update response: %s\", ct) }","typeGuard":"func isParseUpdateErr(err error) bool {\n\treturn strings.Contains(err.Error(), \"failed to parse update response\")\n}","tryCatchPattern":"issue, err := client.UpdateIssue(ctx, iid, updates)\nif err != nil {\n\tif isParseUpdateErr(err) {\n\t\t// the PUT may have succeeded; re-fetch by IID to confirm instead of retrying the write\n\t\treturn client.FetchIssueByIID(ctx, iid)\n\t}\n\treturn err\n}","preventionTips":["Do not blindly retry updates after parse errors — re-fetch to confirm state","Bypass response-rewriting middleware for API calls","Keep Issue struct in sync with your GitLab version","Log the failing body to detect schema drift early"],"tags":["gitlab","json","network"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}