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

  1. Remove the circular reference from the argument before passing it, e.g. break the cycle or pass a copy without back-references
  2. Serialize to a flat representation (JSON round-trip the value) which fails on cycles and exposes the offending field
  3. 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

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


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)