{"record":{"id":"afd017b3a47d7c53","repo":"gastownhall/beads","slug":"reparent-childid-must-not-be-empty","errorCode":null,"errorMessage":"reparent: childID must not be empty","messagePattern":"reparent: childID must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/dependency.go","lineNumber":382,"sourceCode":"\t\treturn fmt.Errorf(\"remove dep: sourceID and dependsOnID must not be empty\")\n\t}\n\tif _, err := u.depRepo.Delete(ctx, sourceID, dependsOnID, actor, DepInsertOpts{UseWispsTable: useWisp, EmitEvent: true}); err != nil {\n\t\treturn fmt.Errorf(\"remove dep %s -> %s: %w\", sourceID, dependsOnID, err)\n\t}\n\treturn nil\n}\n\nfunc (u *dependencyUseCaseImpl) Reparent(ctx context.Context, childID, newParentID, actor string) error {\n\treturn u.reparent(ctx, childID, newParentID, actor, false)\n}\n\nfunc (u *dependencyUseCaseImpl) ReparentWisp(ctx context.Context, childWispID, newParentID, actor string) error {\n\treturn u.reparent(ctx, childWispID, newParentID, actor, true)\n}\n\nfunc (u *dependencyUseCaseImpl) reparent(ctx context.Context, childID, newParentID, actor string, useWisp bool) error {\n\tif childID == \"\" {\n\t\treturn fmt.Errorf(\"reparent: childID must not be empty\")\n\t}\n\tif childID == newParentID {\n\t\treturn fmt.Errorf(\"reparent: %s cannot be its own parent\", childID)\n\t}\n\n\topts := DepInsertOpts{UseWispsTable: useWisp}\n\tres, err := u.depRepo.ListByIssueIDs(ctx, []string{childID}, DepListOpts{\n\t\tTypes:         []types.DependencyType{types.DepParentChild},\n\t\tDirection:     DepDirectionOut,\n\t\tUseWispsTable: useWisp,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reparent: list current parent: %w\", err)\n\t}\n\n\t// A child can carry MORE THAN ONE parent-child edge — Create accepts\n\t// CreateRequest.ParentID and an explicit parent-child entry in\n\t// Dependencies in the same request — so this is a set replacement, not a","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/dependency.go#L364-L400","documentation":"Guard error from reparent (backing Reparent and ReparentWisp): childID is the empty string. Reparenting requires knowing which child to move; the use case refuses before any repository work. A newParentID of \"\" is not caught here explicitly (only the childID==newParentID equality check follows), so the empty child is the guarded precondition.","triggerScenarios":"Reparent(ctx, \"\", parentID, actor) or ReparentWisp with an empty child ID — usually a failed upstream lookup, a blank CLI argument, or a struct field left at its zero value before the call.","commonSituations":"Scripts re-parenting issues from a list where one ID failed to resolve; YAML/JSON config with a missing child key; passing a *types.Issue whose ID was never persisted.","solutions":["Check childID for emptiness before calling Reparent / ReparentWisp.","Resolve the child issue via lookup first and abort with a clear message if it cannot be found.","Fix the upstream parse/config that produced the blank ID.","In batch reparent jobs, skip or log entries with empty IDs instead of passing them through."],"exampleFix":"// before\nerr := uc.Reparent(ctx, childID, newParentID, actor)\n// after\nif childID == \"\" {\n    return fmt.Errorf(\"reparent skipped: child id missing\")\n}\nerr := uc.Reparent(ctx, childID, newParentID, actor)","handlingStrategy":"validation","validationCode":"func readyToReparent(childID, newParentID string) error {\n    if childID == \"\" {\n        return fmt.Errorf(\"childID must not be empty\")\n    }\n    if childID == newParentID {\n        return fmt.Errorf(\"child cannot be its own parent\")\n    }\n    return nil\n}\nif err := readyToReparent(childID, newParentID); err != nil {\n    return err\n}\nerr := uc.Reparent(ctx, childID, newParentID, actor)","typeGuard":"func validChildID(id string) bool { return id != \"\" }","tryCatchPattern":"if !validChildID(childID) {\n    return fmt.Errorf(\"reparent skipped: missing child id\")\n}\nif err := uc.Reparent(ctx, childID, newParentID, actor); err != nil {\n    return fmt.Errorf(\"reparent failed: %w\", err)\n}","preventionTips":["Resolve and verify the child issue exists before reparent calls","Skip/log empty IDs in batch reparent jobs","Fail fast on failed upstream lookups instead of forwarding empty IDs","Validate CLI/config inputs at parse time"],"tags":["go","validation","reparent","empty-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}