{"record":{"id":"0d67600d818e36c2","repo":"gastownhall/beads","slug":"deps-cannot-attach-both-q-and-q-to-the-same-ta","errorCode":null,"errorMessage":"--deps cannot attach both %q and %q to the same target %q: a target can only carry one dependency type at a time. Pick one type, or open a separate issue for the second relationship (GH#4626)","messagePattern":"--deps cannot attach both %q and %q to the same target %q: a target can only carry one dependency type at a time\\. Pick one type, or open a separate issue for the second relationship \\(GH#4626\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/create_deps.go","lineNumber":84,"sourceCode":"// would collide on the (issue_id, target) dependency-uniqueness key with a\n// *different* type. Type is not part of that key, so two different types on\n// the same target can't both be stored — but the storage layer already\n// treats a repeated identical (target, type) add as idempotent, so an exact\n// repeat here must be deduped rather than rejected.\n// GH#4626: discovered-from:X,blocked-by:X used to silently keep only one edge.\nfunc dedupeDepSpecs(specs []domain.DependencySpec) ([]domain.DependencySpec, error) {\n\t// Key: swapDirection|target — same effective endpoint pair for a new issue.\n\tseen := make(map[string]types.DependencyType, len(specs))\n\tout := make([]domain.DependencySpec, 0, len(specs))\n\tfor _, s := range specs {\n\t\tkey := fmt.Sprintf(\"%t|%s\", s.SwapDirection, s.TargetID)\n\t\tprev, ok := seen[key]\n\t\tswitch {\n\t\tcase !ok:\n\t\t\tseen[key] = s.Type\n\t\t\tout = append(out, s)\n\t\tcase prev != s.Type:\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"--deps cannot attach both %q and %q to the same target %q: a target can only carry one dependency type at a time. Pick one type, or open a separate issue for the second relationship (GH#4626)\",\n\t\t\t\tprev, s.Type, s.TargetID,\n\t\t\t)\n\t\tdefault:\n\t\t\t// Identical edge repeated (e.g. blocked-by and depends-on both\n\t\t\t// normalize to the same type/target) — silently dedupe.\n\t\t}\n\t}\n\tif len(out) == 0 {\n\t\treturn nil, nil\n\t}\n\treturn out, nil\n}\n\n// resolveDepSpecTargets rewrites each non-external TargetID through the same\n// partial-ID resolution path as `bd dep add` (utils.ResolvePartialID).\n//\n// Without this, `bd create --deps discovered-from:8vezf` stores the bare","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/create_deps.go#L66-L102","documentation":"`bd create --deps` normalizes each spec's (type,target) pair and silently dedupes identical duplicates, but if the SAME target appears with TWO DIFFERENT dependency types (e.g. both \"blocks:bd-5\" and \"related:bd-5\") the parse fails. The CLI deliberately rejects this because a target can carry only one dependency edge type from a single create, and the intent is ambiguous. The message cites GH#4626 for the design rationale.","triggerScenarios":"Calling `bd create ... --deps \"blocks:bd-5,related:bd-5\"` (or building the same via createIssueWithDeps/parseDepSpecs) where two specs in the comma list share TargetID but differ in Type after canonicalization (depends-on/blocked-by both canonicalize to blocks, so those duplicates are fine — only genuinely different types collide).","commonSituations":"Script-generated --deps lists assembled from multiple sources (e.g. CI templates plus hand-written flags) that both reference the same issue with different relation semantics; users confusing 'blocked-by X' with 'related to X' and listing both.","solutions":["Remove one of the conflicting specs so the target appears once with a single type","Open a separate issue or run a second `bd dep add` for the second relationship, as the message suggests","Decide the intended semantics: blocked-by and depends-on are aliases of the same canonical type and dedupe harmlessly — use the alias form if both spellings meant the same edge"],"exampleFix":"// before\nbd create \"Task\" --deps \"blocks:bd-5,related:bd-5\"\n// after\nbd create \"Task\" --deps \"blocks:bd-5\"\nbd dep add bd-5 --type related --target bd-5   # second relationship separately","handlingStrategy":"validation","validationCode":"func checkSingleTypePerTarget(deps string) error {\n    seen := map[string]string{}\n    for _, part := range strings.Split(deps, \",\") {\n        fields := strings.SplitN(strings.TrimSpace(part), \":\", 2)\n        var typ, target string\n        if len(fields) == 2 { typ, target = fields[0], fields[1] } else { target = fields[0] }\n        if prev, ok := seen[target]; ok && prev != typ {\n            return fmt.Errorf(\"target %q has conflicting types %q and %q\", target, prev, typ)\n        }\n        seen[target] = typ\n    }\n    return nil\n}\n// run before composing the --deps flag","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build the deps list from a map keyed by target so each target can only carry one type","Remember depends-on/blocked-by are aliases of blocks — don't mix them with other types on the same target","Emit the second relationship via a separate `bd dep add` call"],"tags":["cli","dependencies","validation","argument-conflict"],"backgroundTag":"conflicting-dependency-types","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}