{"record":{"id":"06282d2724073a4b","repo":"gastownhall/beads","slug":"deletewisp-id-must-not-be-empty","errorCode":null,"errorMessage":"DeleteWisp: id must not be empty","messagePattern":"DeleteWisp: id must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":42,"sourceCode":"\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}\n\nfunc (u *issueUseCaseImpl) DeleteIssues(ctx context.Context, params DeleteIssuesParams, actor string) (DeleteIssuesResult, error) {\n\treturn u.deleteMany(ctx, params, actor)\n}\n\nfunc (u *issueUseCaseImpl) DeleteWisps(ctx context.Context, params DeleteIssuesParams, actor string) (DeleteIssuesResult, error) {\n\treturn u.deleteMany(ctx, params, actor)\n}\n\nfunc (u *issueUseCaseImpl) PreviewDelete(ctx context.Context, ids []string) (DeletePreview, error) {\n\treturn u.previewDelete(ctx, ids)","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L24-L60","documentation":"DeleteWisp validates its required id argument before doing any work and returns this error when the id is an empty string. Like DeleteIssue, it is an input-validation guard at the use-case layer; no storage call occurs. It applies to wisp (ephemeral issue) deletion.","triggerScenarios":"Calling DeleteWisp(ctx, \"\", actor) — an uninitialized wisp ID, a failed wisp lookup returning an empty ID, or whitespace-only input that was trimmed to \"\".","commonSituations":"Agent loops deleting wisps from a batch where some entries lack IDs; reading wisp IDs from JSONL export files with missing fields; variable shadowing leaving the ID unset.","solutions":["Pass the real wisp ID to DeleteWisp","Validate the wisp ID exists at the source (lookup result, JSON field) before calling","Skip empty entries in batch-delete loops instead of passing them through"],"exampleFix":"// before\nfor _, w := range wisps {\n\tuc.DeleteWisp(ctx, w.ID, actor) // panics the flow with empty-id error\n}\n// after\nfor _, w := range wisps {\n\tif w.ID == \"\" { continue }\n\tuc.DeleteWisp(ctx, w.ID, actor)\n}","handlingStrategy":"validation","validationCode":"for _, w := range wisps {\n\tif strings.TrimSpace(w.ID) == \"\" { continue } // skip malformed entries\n\tif _, err := uc.DeleteWisp(ctx, w.ID, actor); err != nil { return err }\n}","typeGuard":"func hasWispID(w Wisp) bool { return strings.TrimSpace(w.ID) != \"\" }","tryCatchPattern":"res, err := uc.DeleteWisp(ctx, id, actor)\nif err != nil && strings.Contains(err.Error(), \"DeleteWisp: id must not be empty\") {\n\tlog.Printf(\"skipping: empty wisp id\")\n\treturn nil\n}","preventionTips":["Filter out entries with missing IDs before batch wisp deletion","Validate JSONL/export records before loading them into delete flows","Check lookup results for success before reusing the returned ID"],"tags":["go","validation","wisp","empty-argument"],"backgroundTag":"empty-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}