AdguardTeam/AdGuardHome · error

unexpected type of %q: %T

Error message

unexpected type of %q: %T

What it means

The generic YAML field-lookup helper fieldVal[T] found a value for the key but its dynamic type did not match the requested Go type T. This fires across many migration steps (v10–v14) whenever a config field's decoded type differs from what the migration expects (usually string).

Source

Thrown at internal/configmigrate/yaml.go:29

	// yobj is the convenience alias for YAML key-value object.
	yobj = map[string]any
)

// fieldVal returns the value of type T for key from obj.  Use [any] if the
// field's type doesn't matter.
func fieldVal[T any](obj yobj, key string) (v T, ok bool, err error) {
	val, ok := obj[key]
	if !ok {
		return v, false, nil
	}

	if val == nil {
		return v, true, nil
	}

	v, ok = val.(T)
	if !ok {
		return v, false, fmt.Errorf("unexpected type of %q: %T", key, val)
	}

	return v, true, nil
}

// moveVal copies the value for srcKey from src into dst for dstKey and deletes
// it from src.
func moveVal[T any](src, dst yobj, srcKey, dstKey string) (err error) {
	newVal, ok, err := fieldVal[T](src, srcKey)
	if !ok {
		return err
	}

	dst[dstKey] = newVal
	delete(src, srcKey)

	return nil
}

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Find the key named in the error message in your config.yaml and check its YAML type
  2. Quote the value or restructure it so it decodes as the expected type (usually a string)
  3. Re-run AdGuard Home to complete migration

Example fix

# before
http:\n  address: 80
# after
http:\n  address: 0.0.0.0:80
Defensive patterns

Strategy: validation

Validate before calling

// pre-check a config field decodes as string
if v, ok := m["key"]; ok && v != nil {
    if _, ok := v.(string); !ok { return errors.New("key must be a string") }
}

Type guard

func isString(v any) bool { _, ok := v.(string); return ok }

Prevention

When it happens

Trigger: Running a config migration where a field expected to be a string (e.g. a bind host, scheme, or DNS name) is instead a number, boolean, list, or nested map in the YAML/JSON config.

Common situations: Hand-edited configs, unquoted YAML scalars that decode as int/bool (e.g. bind_host: 3000), or config produced by an incompatible fork/older version.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/42ccdee96e682177. Report an issue: GitHub.