{"record":{"id":"2e87dea55208c250","repo":"gastownhall/beads","slug":"deleteissue-id-must-not-be-empty","errorCode":null,"errorMessage":"DeleteIssue: id must not be empty","messagePattern":"DeleteIssue: id must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":31,"sourceCode":"// DeleteBlockedError is the refusal returned by deleteMany when\n// EnforceCascadePolicy is on, Cascade and Force are both off, and an issue in\n// the deletion set has dependents outside it. The message mirrors classic\n// (embedded) delete's refusal so both planes speak the same language.\ntype DeleteBlockedError struct {\n\t// IssueID is the first issue in the requested deletion set (request order)\n\t// found to have external dependents.\n\tIssueID string\n\t// Dependents are that issue's dependents outside the deletion set, sorted.\n\tDependents []string\n}\n\nfunc (e *DeleteBlockedError) Error() string {\n\treturn fmt.Sprintf(\"issue %s has dependents not in deletion set; use --cascade to delete them or --force to orphan them\", e.IssueID)\n}\n\nfunc (u *issueUseCaseImpl) DeleteIssue(ctx context.Context, id, actor string) (DeleteIssuesResult, error) {\n\tif id == \"\" {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"DeleteIssue: id must not be empty\")\n\t}\n\treturn u.deleteMany(ctx, DeleteIssuesParams{\n\t\tIDs:                  []string{id},\n\t\tCascade:              true,\n\t\tUpdateTextReferences: true,\n\t}, actor)\n}\n\nfunc (u *issueUseCaseImpl) DeleteWisp(ctx context.Context, id, actor string) (DeleteIssuesResult, error) {\n\tif id == \"\" {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"DeleteWisp: id must not be empty\")\n\t}\n\treturn u.deleteMany(ctx, DeleteIssuesParams{\n\t\tIDs:                  []string{id},\n\t\tCascade:              true,\n\t\tUpdateTextReferences: true,\n\t}, actor)\n}","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L13-L49","documentation":"DeleteIssue validates its required id argument before doing any work and returns this error when the id is an empty string. It is a pure input-validation guard in the use-case layer; no storage call is made. The caller passed an uninitialized or stripped issue ID.","triggerScenarios":"Calling DeleteIssue(ctx, \"\", actor) — e.g. an issue ID variable that was never populated, a struct field left zero-valued, or a string-trimming bug that reduced the ID to \"\".","commonSituations":"Scripts parsing issue IDs from JSON or CLI output where the key is missing; agent code building delete calls from empty lookup results; passing a zero-value string from a struct.","solutions":["Pass the actual issue ID (e.g. \"bd-42\") to DeleteIssue instead of an empty string","Check where the ID is sourced (config, JSON, lookup result) and handle the missing-ID case before calling","Add a caller-side check: if id == \"\" return a clear user-facing message before invoking the API"],"exampleFix":"// before\nres, err := uc.DeleteIssue(ctx, issue.ID, actor) // issue.ID may be \"\"\n// after\nif issue.ID == \"\" {\n\treturn fmt.Errorf(\"cannot delete: no issue ID provided\")\n}\nres, err := uc.DeleteIssue(ctx, issue.ID, actor)","handlingStrategy":"validation","validationCode":"func deleteIssue(id, actor string) error {\n\tif strings.TrimSpace(id) == \"\" {\n\t\treturn fmt.Errorf(\"refusing to delete: issue id is empty\")\n\t}\n\t_, err := uc.DeleteIssue(ctx, id, actor)\n\treturn err\n}","typeGuard":"func hasID(id string) bool { return strings.TrimSpace(id) != \"\" }","tryCatchPattern":"res, err := uc.DeleteIssue(ctx, id, actor)\nif err != nil && strings.Contains(err.Error(), \"id must not be empty\") {\n\treturn fmt.Errorf(\"caller bug: empty issue id passed to DeleteIssue\")\n}","preventionTips":["Never build delete calls from zero-value struct fields","Validate IDs at the source (CLI args, JSON fields) before storage calls","Return early on empty lookup results instead of propagating empty IDs"],"tags":["go","validation","delete","empty-argument"],"backgroundTag":"empty-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}