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
- Find the key named in the error message in your config.yaml and check its YAML type
- Quote the value or restructure it so it decodes as the expected type (usually a string)
- 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
- Quote YAML scalars that look like numbers/bools
- Test migrations in CI with sample configs
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
- unexpected type of upstream field: %T
- persistent client at index %d: unexpected type %T
- filters: at index %d: expected object, got %T
- parsing config file for upgrade: %w
- generating new config: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/42ccdee96e682177.
Report an issue: GitHub.