microsoft/aspire · error
argument ' ' passed to capability ' ' contains a circular…
Error message
argument '%s' passed to capability '%s' contains a circular reference
What it means
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.
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
Example fix
// before
type Node struct { Next *Node }
n := &Node{}
n.Next = n // cycle
client.Capability(ctx, n)
// after
type Node struct { Next *Node }
n := &Node{}
copy := &Node{} // no cycle
client.Capability(ctx, copy) Defensive patterns
Strategy: validation
Validate before calling
func hasCycle(v any, seen map[uintptr]bool) bool {
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr, reflect.Map, reflect.Slice:
if rv.IsNil() { return false }
p := rv.Pointer()
if seen[p] { return true }
seen[p] = true
switch rv.Kind() {
case reflect.Map:
for _, k := range rv.MapKeys() {
if hasCycle(rv.MapIndex(k).Interface(), seen) { return true }
if hasCycle(k.Interface(), seen) { return true }
}
case reflect.Slice:
for i := 0; i < rv.Len(); i++ {
if hasCycle(rv.Index(i).Interface(), seen) { return true }
}
case reflect.Ptr:
return hasCycle(rv.Elem().Interface(), seen)
}
}
return false
} Type guard
if hasCycle(arg, map[uintptr]bool{}) { return errors.New("argument contains a circular reference") } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- aspire: build returned unexpected type %T
- aspire: returned unexpected type %T
- aspire: createBuilder returned unexpected type %T
- aspire: deep update recursion limit of '32' exceeded
- aspire: merge type mismatch: cannot merge
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/445dfa97567f7bc3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go:892
}
ancestors := make(map[uintptr]struct{})
return validateValue(args, "args", ancestors, capabilityID)
}
func validateValue(value any, path string, ancestors map[uintptr]struct{}, capabilityID string) error {
if value == nil {
return nil
}
val := reflect.ValueOf(value)
switch val.Kind() {
case reflect.Map, reflect.Slice, reflect.Ptr:
if val.IsNil() {
return nil
}
ptr := val.Pointer()
if _, ok := ancestors[ptr]; ok {
return fmt.Errorf("argument '%s' passed to capability '%s' contains a circular reference", path, capabilityID)
}
ancestors[ptr] = struct{}{}
defer delete(ancestors, ptr)
default:
}
switch v := value.(type) {
case map[string]any:
for key, nestedValue := range v {
if err := validateValue(nestedValue, path+"."+key, ancestors, capabilityID); err != nil {
return err
}
}
case []any:
for i, item := range v {
if err := validateValue(item, fmt.Sprintf("%s[%d]", path, i), ancestors, capabilityID); err != nil {
return err
}View on GitHub (pinned to 25830f84bd)