{"record":{"id":"64f34170a999ccdb","repo":"gastownhall/beads","slug":"errselfdependency-64f341","errorCode":"ErrSelfDependency","errorMessage":"%w: %s","messagePattern":"%w: %s","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/uow/batch_applier.go","lineNumber":385,"sourceCode":"// WHETHER THE EDGE WAS NEW IS READ BEFORE THE WRITE, because this backend's\n// insert does not report it: BulkAddDepsResult echoes the request. A pre-read\n// per edge is bounded by the request's hundred-item cap and is the only way\n// ItemResult.Changed can mean the same thing on all three legs — an idempotent\n// re-add of the same pair with the same type changed nothing.\nfunc (r *uowApplyRun) applyDepAdd(ctx context.Context, index int, item *publicops.DepAddItem) error {\n\tsource, err := r.resolve(item.Source, index, \"source\")\n\tif err != nil {\n\t\treturn err\n\t}\n\ttarget, err := r.resolve(item.Target, index, \"target\")\n\tif err != nil {\n\t\treturn err\n\t}\n\titemErr := func(err error) error {\n\t\treturn &publicops.ItemError{Index: index, Kind: publicops.ItemDepAdd, Key: item.Source.Key, IssueID: source, Err: err}\n\t}\n\tif source == target {\n\t\treturn itemErr(fmt.Errorf(\"%w: %s\", publicops.ErrSelfDependency, source))\n\t}\n\tsourceWisp, sourceMine := r.planes[source]\n\ttargetWisp, targetMine := r.planes[target]\n\tif sourceMine && targetMine && sourceWisp != targetWisp {\n\t\treturn itemErr(storageissueops.CrossPlaneBatchEdgeError(source, target))\n\t}\n\texisted, err := r.edgeExists(ctx, source, target, item.Type)\n\tif err != nil {\n\t\treturn itemErr(err)\n\t}\n\tdep := &types.Dependency{\n\t\tIssueID:     source,\n\t\tDependsOnID: target,\n\t\tType:        item.Type,\n\t\tMetadata:    item.Metadata,\n\t}\n\tif _, err := r.uw.DependencyUseCase().AddDependencies(ctx, []*types.Dependency{dep}, r.plan.Actor, domain.BulkAddDepsOpts{\n\t\tSkipPerEdgeCycleCheck: r.plan.SkipPerEdgeCycleCheck,","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/batch_applier.go#L367-L403","documentation":"A dependency-add batch item tried to make an issue depend on itself, which is forbidden. The error is wrapped in publicops.ErrSelfDependency and again in an ItemError carrying the batch index and source key so callers can attribute the failure to one item.","triggerScenarios":"applyDepAdd receives a DepAdd item where item.Source.Key resolves to the same issue id as the target (source == target). E.g. 'bd dep add bd-1 bd-1' or a programmatic batch with identical source and target keys.","commonSituations":"Template-generated batch scripts where a variable accidentally equals the source id; loops that include the seed issue in its own dependency list; copy-paste of the same issue id into both fields.","solutions":["Fix the batch/CLI input so source and target differ","Pre-filter items where Source.Key == DependsOn.Key before submitting the batch","Assert source != target where the dependency list is generated programmatically"],"exampleFix":"// before\nif source == target { return itemErr(...) } // rejected at apply time\n// after (caller-side)\nfor _, it := range items {\n    if it.DepAdd.Source.Key == it.DepAdd.DependsOn.Key { continue } // skip self-dep\n}","handlingStrategy":"validation","validationCode":"for i, it := range items {\n    if it.DepAdd != nil && it.DepAdd.Source.Key == it.DepAdd.DependsOn.Key {\n        return fmt.Errorf(\"item %d: self-dependency on %s\", i, it.DepAdd.Source.Key)\n    }\n}","typeGuard":null,"tryCatchPattern":"err := applyBatch(ctx, batch)\nvar itemErr *publicops.ItemError\nif errors.As(err, &itemErr) && errors.Is(itemErr.Err, publicops.ErrSelfDependency) {\n    log.Printf(\"batch item %d (%s): self-dependency\", itemErr.Index, itemErr.Key)\n}","preventionTips":["Filter source == target items before submitting batches","Assert non-self edges where dependency lists are generated","Treat issue ids as immutable keys when templating scripts","Add a unit test that no generated batch contains self-edges"],"tags":["validation","dependencies","batch","cycle"],"backgroundTag":"self-dependency","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}