{"record":{"id":"42ccdee96e682177","repo":"AdguardTeam/AdGuardHome","slug":"unexpected-type-of-q-t","errorCode":null,"errorMessage":"unexpected type of %q: %T","messagePattern":"unexpected type of %q: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configmigrate/yaml.go","lineNumber":29,"sourceCode":"\t// yobj is the convenience alias for YAML key-value object.\n\tyobj = map[string]any\n)\n\n// fieldVal returns the value of type T for key from obj.  Use [any] if the\n// field's type doesn't matter.\nfunc fieldVal[T any](obj yobj, key string) (v T, ok bool, err error) {\n\tval, ok := obj[key]\n\tif !ok {\n\t\treturn v, false, nil\n\t}\n\n\tif val == nil {\n\t\treturn v, true, nil\n\t}\n\n\tv, ok = val.(T)\n\tif !ok {\n\t\treturn v, false, fmt.Errorf(\"unexpected type of %q: %T\", key, val)\n\t}\n\n\treturn v, true, nil\n}\n\n// moveVal copies the value for srcKey from src into dst for dstKey and deletes\n// it from src.\nfunc moveVal[T any](src, dst yobj, srcKey, dstKey string) (err error) {\n\tnewVal, ok, err := fieldVal[T](src, srcKey)\n\tif !ok {\n\t\treturn err\n\t}\n\n\tdst[dstKey] = newVal\n\tdelete(src, srcKey)\n\n\treturn nil\n}","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/configmigrate/yaml.go#L11-L47","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nhttp:\\n  address: 80\n# after\nhttp:\\n  address: 0.0.0.0:80","handlingStrategy":"validation","validationCode":"// pre-check a config field decodes as string\nif v, ok := m[\"key\"]; ok && v != nil {\n    if _, ok := v.(string); !ok { return errors.New(\"key must be a string\") }\n}","typeGuard":"func isString(v any) bool { _, ok := v.(string); return ok }","tryCatchPattern":null,"preventionTips":["Quote YAML scalars that look like numbers/bools","Test migrations in CI with sample configs"],"tags":["config","migration","yaml","type-mismatch"],"backgroundTag":"config-schema-migration-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}