{"record":{"id":"c595af7040ebe60e","repo":"gastownhall/beads","slug":"issue-must-not-be-nil","errorCode":null,"errorMessage":"issue must not be nil","messagePattern":"issue must not be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/issues.go","lineNumber":31,"sourceCode":"\t\"go.opentelemetry.io/otel/metric\"\n\n\t\"github.com/steveyegge/beads/internal/idgen\"\n\t\"github.com/steveyegge/beads/internal/storage\"\n\t\"github.com/steveyegge/beads/internal/storage/issueops\"\n\t\"github.com/steveyegge/beads/internal/types\"\n)\n\n// CreateIssue creates a new issue.\n// Delegates SQL work to issueops; handles Dolt versioning for non-ephemeral issues.\nfunc (s *DoltStore) CreateIssue(ctx context.Context, issue *types.Issue, actor string) error {\n\treturn s.withCircuitWrite(ctx, func(ctx context.Context) error {\n\t\treturn s.createIssue(ctx, issue, actor)\n\t})\n}\n\nfunc (s *DoltStore) createIssue(ctx context.Context, issue *types.Issue, actor string) error {\n\tif issue == nil {\n\t\treturn fmt.Errorf(\"issue must not be nil\")\n\t}\n\n\t// Route to wisps table if ephemeral, no-history, wisp-typed, or infra type.\n\t// A wisp_type is a claim of ephemerality: minted without the flag it lands\n\t// in the issues plane where no TTL, GC, or purge tier owns it.\n\tuseWispsTable := issue.Ephemeral || issue.NoHistory || issue.WispType != \"\" || s.IsInfraTypeCtx(ctx, issue.IssueType)\n\tif useWispsTable && !issue.NoHistory {\n\t\tissue.Ephemeral = true // infra and wisp types get marked ephemeral (legacy behavior)\n\t}\n\n\tvar result issueops.CreateIssueResult\n\tif err := s.withRetryTx(ctx, func(tx *sql.Tx) error {\n\t\t// SkipPrefixValidation matches legacy behavior: single-issue path does\n\t\t// not validate prefixes for explicit IDs.\n\t\tbc, err := issueops.NewBatchContext(ctx, tx, storage.BatchCreateOptions{\n\t\t\tSkipPrefixValidation: true,\n\t\t})\n\t\tif err != nil {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/issues.go#L13-L49","documentation":"createIssue (and its exported wrapper CreateIssue) rejects a nil *types.Issue pointer before doing any work. This is a programmer-error guard: passing nil means no issue data exists to persist, so the library returns a clear error instead of panicking on a nil dereference.","triggerScenarios":"Calling store.CreateIssue(ctx, nil, actor) — e.g. a variable that failed to initialize, a function that returns (issue, err) where issue is nil on an ignored error path, or decoding empty input into a nil pointer.","commonSituations":"JSON payloads that deserialize to a nil issue when a required field check is skipped; refactored code paths where an earlier error was swallowed and the zero-value (nil) pointer flowed onward; test harnesses passing nil placeholders.","solutions":["Ensure a non-nil *types.Issue with required fields (Title, etc.) is constructed before calling CreateIssue.","Check the error return of whatever produced the issue pointer — a nil issue usually indicates an earlier ignored error.","In wrappers/CLIs, validate decoded input and return a user-facing 'issue data required' message instead of passing nil through."],"exampleFix":"// before\nvar issue *types.Issue // nil unless populated\njson.Unmarshal(body, &issue) // may leave issue nil on empty body\nstore.CreateIssue(ctx, issue, actor) // \"issue must not be nil\"\n// after\nissue := &types.Issue{}\nif err := json.Unmarshal(body, issue); err != nil { return err }\nif issue.Title == \"\" { return fmt.Errorf(\"title required\") }\nstore.CreateIssue(ctx, issue, actor)","handlingStrategy":"type-guard","validationCode":"if issue == nil || issue.Title == \"\" { return fmt.Errorf(\"issue with non-empty title required\") }\nstore.CreateIssue(ctx, issue, actor)","typeGuard":"func hasIssue(i *types.Issue) bool { return i != nil }","tryCatchPattern":"if err := store.CreateIssue(ctx, issue, actor); err != nil {\n    if strings.Contains(err.Error(), \"issue must not be nil\") {\n        return fmt.Errorf(\"no issue data provided (check upstream error handling)\")\n    }\n    return err\n}","preventionTips":["Always check the error return of functions that produce *types.Issue before using the pointer.","Construct issues with struct literals, not nil var declarations.","Validate required fields (Title, IssueType) before calling create APIs."],"tags":["nil-pointer","validation","api-misuse","issues"],"backgroundTag":"nil-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}