{"record":{"id":"445dfa97567f7bc3","repo":"microsoft/aspire","slug":"argument-s-passed-to-capability-s-contains-a-circular","errorCode":null,"errorMessage":"argument '%s' passed to capability '%s' contains a circular reference","messagePattern":"argument '(.+?)' passed to capability '(.+?)' contains a circular reference","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go","lineNumber":892,"sourceCode":"\t}\n\tancestors := make(map[uintptr]struct{})\n\treturn validateValue(args, \"args\", ancestors, capabilityID)\n}\n\nfunc validateValue(value any, path string, ancestors map[uintptr]struct{}, capabilityID string) error {\n\tif value == nil {\n\t\treturn nil\n\t}\n\n\tval := reflect.ValueOf(value)\n\tswitch val.Kind() {\n\tcase reflect.Map, reflect.Slice, reflect.Ptr:\n\t\tif val.IsNil() {\n\t\t\treturn nil\n\t\t}\n\t\tptr := val.Pointer()\n\t\tif _, ok := ancestors[ptr]; ok {\n\t\t\treturn fmt.Errorf(\"argument '%s' passed to capability '%s' contains a circular reference\", path, capabilityID)\n\t\t}\n\t\tancestors[ptr] = struct{}{}\n\t\tdefer delete(ancestors, ptr)\n\tdefault:\n\t}\n\n\tswitch v := value.(type) {\n\tcase map[string]any:\n\t\tfor key, nestedValue := range v {\n\t\t\tif err := validateValue(nestedValue, path+\".\"+key, ancestors, capabilityID); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase []any:\n\t\tfor i, item := range v {\n\t\t\tif err := validateValue(item, fmt.Sprintf(\"%s[%d]\", path, i), ancestors, capabilityID); err != nil {\n\t\t\t\treturn err\n\t\t\t}","sourceCodeStart":874,"sourceCodeEnd":910,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go#L874-L910","documentation":"This error comes from generated Go transport code that walks argument values via reflection before sending them to an ATS capability. When it encounters a map, slice, or pointer whose identity (pointer address) is already in the ancestor set, the value graph is cyclic and could cause infinite recursion or a payload the wire format cannot represent, so it fails fast with this message.","triggerScenarios":"Passing an argument containing a reference cycle — e.g. a struct with a pointer to itself, a map value that maps back to a containing slice, or a linked list with a loop — into a generated capability method.","commonSituations":"Building linked object graphs by hand (parent/child pointers), accidental self-referencing slices, or reusing a data structure that contains a back-reference such as a node pointing to its container.","solutions":["Remove the circular reference from the argument before passing it, e.g. break the cycle or pass a copy without back-references","Serialize to a flat representation (JSON round-trip the value) which fails on cycles and exposes the offending field","Refactor the data model so child nodes reference parents by key/ID rather than by pointer"],"exampleFix":"// before\ntype Node struct { Next *Node }\nn := &Node{}\nn.Next = n // cycle\nclient.Capability(ctx, n)\n// after\ntype Node struct { Next *Node }\nn := &Node{}\ncopy := &Node{} // no cycle\nclient.Capability(ctx, copy)","handlingStrategy":"validation","validationCode":"func hasCycle(v any, seen map[uintptr]bool) bool {\n\trv := reflect.ValueOf(v)\n\tswitch rv.Kind() {\n\tcase reflect.Ptr, reflect.Map, reflect.Slice:\n\t\tif rv.IsNil() { return false }\n\t\tp := rv.Pointer()\n\t\tif seen[p] { return true }\n\t\tseen[p] = true\n\t\tswitch rv.Kind() {\n\t\tcase reflect.Map:\n\t\t\tfor _, k := range rv.MapKeys() {\n\t\t\t\tif hasCycle(rv.MapIndex(k).Interface(), seen) { return true }\n\t\t\t\tif hasCycle(k.Interface(), seen) { return true }\n\t\t\t}\n\t\tcase reflect.Slice:\n\t\t\tfor i := 0; i < rv.Len(); i++ {\n\t\t\t\tif hasCycle(rv.Index(i).Interface(), seen) { return true }\n\t\t\t}\n\t\tcase reflect.Ptr:\n\t\t\treturn hasCycle(rv.Elem().Interface(), seen)\n\t\t}\n\t}\n\treturn false\n}","typeGuard":"if hasCycle(arg, map[uintptr]bool{}) { return errors.New(\"argument contains a circular reference\") }","tryCatchPattern":null,"preventionTips":["Model parent links as IDs/keys, not pointers","Never let test fixtures share mutating pointers back into themselves","Round-trip complex args through JSON during development to surface cycles early"],"tags":["go","reflection","circular-reference","code-generation"],"backgroundTag":"invalid-argument-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}