gastownhall/beads · error
create issue: %w
Error message
create issue: %w
What it means
CreateIssue wraps doRequest errors for POST /issue. The issue-creation HTTP call failed: validation error (400), auth/permission failure (401/403), or transport problem. The library throws it so callers know no issue was created (or creation was rejected) before any hydration happens.
Source
Thrown at internal/jira/client.go:265
}
return &issue, nil
}
// CreateIssue creates a new issue in Jira.
// fields should include "project", "summary", "issuetype", and optionally other fields.
func (c *Client) CreateIssue(ctx context.Context, fields map[string]interface{}) (*Issue, error) {
payload := map[string]interface{}{"fields": fields}
data, err := json.Marshal(payload)
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}View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped error's HTTP status and Jira error messages: 400 responses list which fields are invalid.
- Verify project key and issuetype name exactly match the instance (query createmeta if unsure).
- For 401/403, fix the API token and confirm the account has Create Issues permission in the target project.
- If 429, add backoff/jitter between creations.
- Note the issue may have been created despite later errors — check Jira before retrying blindly.
Example fix
// before
issue, err := client.CreateIssue(ctx, map[string]interface{}{
"project": map[string]string{"key": "PROJ"},
"summary": "t", // missing issuetype -> 400
})
// after
issue, err := client.CreateIssue(ctx, map[string]interface{}{
"project": map[string]string{"key": "PROJ"},
"summary": "Fix login failure",
"issuetype": map[string]string{"name": "Bug"},
}) Defensive patterns
Strategy: validation
Validate before calling
// Validate required fields and permissions before POST:
func validCreateFields(fields map[string]interface{}) error {
for _, req := range []string{"project", "summary", "issuetype"} {
if _, ok := fields[req]; !ok {
return fmt.Errorf("missing required field %q", req)
}
}
return nil
}
// Preflight: GET /rest/api/3/createmeta?projectKeys=PROJ to confirm issuetype names Type guard
func isPermissionDenied(err error) bool {
return err != nil && strings.Contains(err.Error(), "403")
} Try / catch
issue, err := client.CreateIssue(ctx, fields)
if err != nil {
if strings.Contains(err.Error(), "400") {
// Jira's error body lists invalid fields; log and fix fields before retry
log.Printf("create rejected: %v — check project key, issuetype name, custom fields", err)
return
}
if isPermissionDenied(err) {
return fmt.Errorf("account lacks create permission in project: %w", err)
}
// 429/5xx/timeouts: retry with backoff, but check for partial creation first
return retryWithBackoff(func() error { _, err = client.CreateIssue(ctx, fields); return err })
} Prevention
- Always include project, summary, and issuetype; verify names against createmeta
- Grant the integration account Create Issues permission in target projects
- Add backoff/jitter for bulk creation to avoid 429s
- Before retrying after unknown errors, search Jira for the summary to avoid duplicates
When it happens
Trigger: POST /issue rejected with 400 because required fields are missing/invalid (project key, issuetype name, summary), 401/403 from bad token or no create permission, 429 rate limiting, or network failure.
Common situations: Wrong project key or issuetype name (e.g. "Bug" vs "Task" vs localized names); account lacking create-issue permission in the project; expired API token; mandatory custom fields not supplied; bulk creation tripping rate limits.
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
- search issues: %w
- get issue %s: %w
- no store is open for this workspace
- not found
- no absolute native user directory is available
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c3ce901456933603.
Report an issue: GitHub.