go-delve/delve · error

can not assign to %T.%q: %v

Error message

can not assign to %T.%q: %v

What it means

In starbind (Starlark scripting), assigning to an attribute of a Go struct wrapped as a Starlark value failed: the deferred recover caught an error/panic from the reflect-based SetField path and re-wraps it. It means the field cannot be assigned, e.g. the field is unexported or the value type mismatches the field type.

Source

Thrown at pkg/terminal/starbind/conv.go:197

	r := v.v.FieldByName(name)
	if !r.IsValid() {
		return starlark.None, starlark.NoSuchAttrError(fmt.Sprintf("no field named %q in %T", name, v.v.Interface()))
	}
	return v.env.interfaceToStarlarkValue(r), nil
}

func (v structAsStarlarkValue) SetField(name string, value starlark.Value) (err error) {
	defer func() {
		// reflect.Value.SetInt, SetFloat, etc panic
		ierr := recover()
		if ierr == nil {
			return
		}
		err, _ = ierr.(error)
		if err == nil {
			panic(ierr)
		}
		err = fmt.Errorf("can not assign to %T.%q: %v", v.v.Interface(), name, err)
	}()
	if r, err := v.valueAttr(name); err != nil || r != nil {
		return starlark.NoSuchAttrError(fmt.Sprintf("no field named %s in %T", name, v.v.Interface()))
	}
	r := v.v.FieldByName(name)
	if !r.IsValid() {
		return starlark.NoSuchAttrError(fmt.Sprintf("no field named %q in %T", name, v.v.Interface()))
	}
	switch value := value.(type) {
	case starlark.Int:
		n, ok := value.Int64()
		if !ok {
			return fmt.Errorf("can not assign big integer to %T.%q", v.v.Interface(), name)
		}
		r.SetInt(n)
	case starlark.Float:
		r.SetFloat(float64(value))
	case starlark.String:

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Check the field name spelling and that it exists in the current Delve API
  2. Only assign exported, mutable struct fields from Starlark
  3. Convert the value to the field's Go type (e.g. starlark.String vs int field)
  4. Use the dedicated API function for read-only fields instead of direct assignment

Example fix

# before
bp.Variable.Value = "x"   # read-only field -> can not assign
# after
bp.Variable = api.Variable{Name: "x"}  # assign via a settable field
Defensive patterns

Strategy: try-catch

Validate before calling

# only assign fields known to be exported and settable
assert field_name in settable_fields_of(obj), "field not assignable: " + field_name

Type guard

def is_assignable_field(v, name):
    f = v.v.Type().FieldByName(name)
    return f is not None and f.IsExported()

Try / catch

try:
    obj.field = value
except Exception as e:
    if "can not assign to" in str(e):
        # fall back to the dedicated API for this field
        set_field_via_api(obj, "field", value)
    else:
        raise

Prevention

When it happens

Trigger: A Starlark script executes `obj.field = value` on a wrapped Go struct where the underlying reflect Set call panics or errors (unexported field, wrong type), and valueAttr did not intercept the name.

Common situations: Scripts written against an older Delve API that renamed/removed a field, or attempts to set computed/read-only fields like Variable.Value directly.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/eb06376d0938f10d. Report an issue: GitHub.