{"record":{"id":"ad8a082e1cdcff10","repo":"gastownhall/beads","slug":"parse-create-response-w","errorCode":null,"errorMessage":"parse create response: %w","messagePattern":"parse create response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/jira/client.go","lineNumber":275,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"marshal create request: %w\", err)\n\t}\n\n\tapiURL := fmt.Sprintf(\"%s/issue\", c.apiBase())\n\n\tbody, err := c.doRequest(ctx, \"POST\", apiURL, data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create issue: %w\", err)\n\t}\n\n\t// Create response only returns id, key, self. Fetch the full issue.\n\tvar created struct {\n\t\tID   string `json:\"id\"`\n\t\tKey  string `json:\"key\"`\n\t\tSelf string `json:\"self\"`\n\t}\n\tif err := json.Unmarshal(body, &created); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse create response: %w\", err)\n\t}\n\n\treturn c.GetIssue(ctx, created.Key)\n}\n\n// UpdateIssue updates an existing Jira issue by key.\nfunc (c *Client) UpdateIssue(ctx context.Context, key string, fields map[string]interface{}) error {\n\tpayload := map[string]interface{}{\"fields\": fields}\n\tdata, err := json.Marshal(payload)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal update request: %w\", err)\n\t}\n\n\tapiURL := fmt.Sprintf(\"%s/issue/%s\", c.apiBase(), url.PathEscape(key))\n\n\t_, err = c.doRequest(ctx, \"PUT\", apiURL, data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"update issue %s: %w\", key, err)","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/jira/client.go#L257-L293","documentation":"CreateIssue wraps json.Unmarshal errors for the POST /issue response. The issue was likely created (2xx) but the body — expected to contain id, key, self — could not be decoded, usually because it's HTML or an unexpected envelope. The library throws it because it needs created.Key to fetch the full issue.","triggerScenarios":"POST /issue returns 2xx with a non-JSON or unexpected body: proxy/SSO HTML injected after success, gateway response wrappers, or an API version whose create response schema differs.","commonSituations":"Corporate proxies rewriting successful responses; custom Jira apps altering create responses; mistyped base URL that happens to accept POST but returns HTML; truncated response bodies on flaky connections. Danger: the issue exists but the caller never learns its key, risking duplicates on retry.","solutions":["Inspect the raw body to confirm whether it's an HTML page or a differently-shaped JSON success object.","Before retrying CreateIssue, search Jira by summary/project to avoid creating duplicates.","Remove proxy/SSO interception for API routes or bypass the gateway for REST calls.","Parse defensively: attempt to extract \"key\" even if the full struct doesn't match."],"exampleFix":"// before\nif err := json.Unmarshal(body, &created); err != nil {\n    return nil, fmt.Errorf(\"parse create response: %w\", err)\n}\n// after: log body and warn that the issue may exist\nif err := json.Unmarshal(body, &created); err != nil {\n    return nil, fmt.Errorf(\"parse create response: %w (issue may have been created; body: %.200s)\", err, string(body))\n}","handlingStrategy":"try-catch","validationCode":"func isJSONBody(b []byte) bool {\n    s := bytes.TrimLeft(b, \" \\t\\r\\n\")\n    return len(s) > 0 && (s[0] == '{' || s[0] == '[')\n}","typeGuard":"func createResponseUsable(b []byte) bool {\n    var c struct{ Key string `json:\"key\"` }\n    return json.Unmarshal(b, &c) == nil && c.Key != \"\"\n}","tryCatchPattern":"issue, err := client.CreateIssue(ctx, fields)\nif err != nil && strings.Contains(err.Error(), \"parse create response\") {\n    // Issue was likely created; DO NOT blindly retry (duplicate risk).\n    // Search by summary to locate or confirm the created issue:\n    found, serr := client.SearchIssues(ctx, fmt.Sprintf(\"project = %s AND summary ~ %q ORDER BY created DESC\", projectKey, summary))\n    if serr == nil && len(found) > 0 {\n        issue = &found[0]\n        err = nil\n    }\n}","preventionTips":["Never retry CreateIssue after a parse failure without first searching for the issue — it likely exists","Exclude REST routes from proxies/gateways that rewrite 2xx responses","Deduplicate by summary+project when creation outcomes are ambiguous","Log raw create-response bodies to detect gateway interference early"],"tags":["jira","json","http-response","go"],"backgroundTag":"invalid-json-response","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}