{"record":{"id":"702a2134a3228fcd","repo":"gastownhall/beads","slug":"close-actor-must-not-be-empty","errorCode":null,"errorMessage":"close: actor must not be empty","messagePattern":"close: actor must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue.go","lineNumber":1668,"sourceCode":"\treturn u.close(ctx, id, params, actor, true)\n}\n\n// CloseIssueChecked closes an issue through the shared guarded close path.\nfunc (u *issueUseCaseImpl) CloseIssueChecked(ctx context.Context, id string, params CloseIssueParams, actor string, force bool) (CloseIssueResult, error) {\n\treturn u.closeChecked(ctx, id, params, actor, force, false)\n}\n\n// CloseWispChecked is the wisp twin of CloseIssueChecked.\nfunc (u *issueUseCaseImpl) CloseWispChecked(ctx context.Context, id string, params CloseIssueParams, actor string, force bool) (CloseIssueResult, error) {\n\treturn u.closeChecked(ctx, id, params, actor, force, true)\n}\n\nfunc (u *issueUseCaseImpl) closeChecked(ctx context.Context, id string, params CloseIssueParams, actor string, force, useWisp bool) (CloseIssueResult, error) {\n\tif id == \"\" {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close: id must not be empty\")\n\t}\n\tif actor == \"\" {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close: actor must not be empty\")\n\t}\n\trow, err := u.issueRepo.CloseChecked(ctx, id, CloseRowParams{Reason: params.Reason, Session: params.Session}, actor, force)\n\tif err != nil {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close %s: %w\", id, err)\n\t}\n\tissue, err := u.issueRepo.Get(ctx, id, IssueTableOpts{UseWispsTable: row.IsWisp || useWisp})\n\tif err != nil {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close %s: reload: %w\", id, err)\n\t}\n\treturn CloseIssueResult{Issue: issue, Closed: !row.AlreadyClosed, OpenChildren: row.OpenChildren}, nil\n}\n\nfunc (u *issueUseCaseImpl) close(ctx context.Context, id string, params CloseIssueParams, actor string, useWisp bool) (CloseIssueResult, error) {\n\tif id == \"\" {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close: id must not be empty\")\n\t}\n\tif actor == \"\" {\n\t\treturn CloseIssueResult{}, fmt.Errorf(\"close: actor must not be empty\")","sourceCodeStart":1650,"sourceCodeEnd":1686,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue.go#L1650-L1686","documentation":"Guard clause in closeChecked: the actor argument is empty. bd records who closed an issue for audit; an empty actor would produce an unattributable close event, so the call is rejected before any storage write.","triggerScenarios":"Calling CloseIssue/CloseWisp/CloseIssueChecked/CloseWispChecked with actor=\"\" — e.g. agent/tooling that never sets the actor name, or config losing the default actor identity.","commonSituations":"CI pipelines with no git user configured; custom integrations omitting the actor parameter; scripts hardcoding \"\" for actor.","solutions":["Pass the real actor (username/agent name) in the close call.","Set up the environment identity (git config user.name or bd's actor config) so defaults resolve.","Validate actor non-empty before invoking the use case.","Fix integration code to thread the authenticated user through to this parameter."],"exampleFix":"// before\nuc.CloseIssue(ctx, id, params, \"\")\n\n// after\nactor := os.Getenv(\"BD_ACTOR\")\nif actor == \"\" { actor = \"unknown-agent\" }\nuc.CloseIssue(ctx, id, params, actor)","handlingStrategy":"validation","validationCode":"func resolveActor(configured string) (string, error) {\n    if configured == \"\" {\n        return \"\", errors.New(\"actor identity missing; set BD_ACTOR or git config user.name\")\n    }\n    return configured, nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"actor must not be empty\") {\n        return fmt.Errorf(\"unauthenticated close: configure an actor identity before closing issues: %w\", err)\n    }\n    return err\n}","preventionTips":["Always thread the authenticated user/agent name into close calls.","Set git config user.name (or equivalent) in CI images.","Reject empty actor at your integration's boundary, not deep in storage.","Log actor on every close for auditability."],"tags":["validation","close","audit","input"],"backgroundTag":"empty-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}