gastownhall/beads · error
parse create response: %w
Error message
parse create response: %w
What it means
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.
Source
Thrown at internal/jira/client.go:275
if err != nil {
return nil, fmt.Errorf("marshal create request: %w", err)
}
apiURL := fmt.Sprintf("%s/issue", c.apiBase())
body, err := c.doRequest(ctx, "POST", apiURL, data)
if err != nil {
return nil, fmt.Errorf("create issue: %w", err)
}
// Create response only returns id, key, self. Fetch the full issue.
var created struct {
ID string `json:"id"`
Key string `json:"key"`
Self string `json:"self"`
}
if err := json.Unmarshal(body, &created); err != nil {
return nil, fmt.Errorf("parse create response: %w", err)
}
return c.GetIssue(ctx, created.Key)
}
// UpdateIssue updates an existing Jira issue by key.
func (c *Client) UpdateIssue(ctx context.Context, key string, fields map[string]interface{}) error {
payload := map[string]interface{}{"fields": fields}
data, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("marshal update request: %w", err)
}
apiURL := fmt.Sprintf("%s/issue/%s", c.apiBase(), url.PathEscape(key))
_, err = c.doRequest(ctx, "PUT", apiURL, data)
if err != nil {
return fmt.Errorf("update issue %s: %w", key, err)View on GitHub (pinned to 71377f2769)
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.
Example fix
// before
if err := json.Unmarshal(body, &created); err != nil {
return nil, fmt.Errorf("parse create response: %w", err)
}
// after: log body and warn that the issue may exist
if err := json.Unmarshal(body, &created); err != nil {
return nil, fmt.Errorf("parse create response: %w (issue may have been created; body: %.200s)", err, string(body))
} Defensive patterns
Strategy: try-catch
Validate before calling
func isJSONBody(b []byte) bool {
s := bytes.TrimLeft(b, " \t\r\n")
return len(s) > 0 && (s[0] == '{' || s[0] == '[')
} Type guard
func createResponseUsable(b []byte) bool {
var c struct{ Key string `json:"key"` }
return json.Unmarshal(b, &c) == nil && c.Key != ""
} Try / catch
issue, err := client.CreateIssue(ctx, fields)
if err != nil && strings.Contains(err.Error(), "parse create response") {
// Issue was likely created; DO NOT blindly retry (duplicate risk).
// Search by summary to locate or confirm the created issue:
found, serr := client.SearchIssues(ctx, fmt.Sprintf("project = %s AND summary ~ %q ORDER BY created DESC", projectKey, summary))
if serr == nil && len(found) > 0 {
issue = &found[0]
err = nil
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- parse Jira response: %w
- parse search response: %w
- parse issue response: %w
- marshal create request: %w
- ExternalDoltConfig: must set Socket or (Host, Port)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ad8a082e1cdcff10.
Report an issue: GitHub.