{"record":{"id":"ae15da67fd9963bc","repo":"AdguardTeam/AdGuardHome","slug":"target-schema-version-d-lower-than-current-d","errorCode":null,"errorMessage":"target schema version %d lower than current %d","messagePattern":"target schema version (.+?) lower than current (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configmigrate/migrator.go","lineNumber":96,"sourceCode":"\tenc := yaml.NewEncoder(buf)\n\tenc.SetIndent(2)\n\n\tif err = enc.Encode(diskConf); err != nil {\n\t\treturn body, false, fmt.Errorf(\"generating new config: %w\", err)\n\t}\n\n\treturn buf.Bytes(), true, nil\n}\n\n// validateVersion validates the current and desired schema versions.\nfunc validateVersion(current, target uint) (err error) {\n\tswitch {\n\tcase current > target:\n\t\treturn fmt.Errorf(\"unknown current schema version %d\", current)\n\tcase target > LastSchemaVersion:\n\t\treturn fmt.Errorf(\"unknown target schema version %d\", target)\n\tcase target < current:\n\t\treturn fmt.Errorf(\"target schema version %d lower than current %d\", target, current)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// migrateFunc is a function that upgrades a config and returns an error.\ntype migrateFunc = func(ctx context.Context, diskConf yobj) (err error)\n\n// upgradeConfigSchema upgrades the configuration schema in diskConf from\n// current to target version.  current must be less than target, and both must\n// be non-negative and less or equal to [LastSchemaVersion].\nfunc (m *Migrator) upgradeConfigSchema(\n\tctx context.Context,\n\tcurrent, target uint,\n\tdiskConf yobj,\n) (err error) {\n\tupgrades := [LastSchemaVersion]migrateFunc{\n\t\t0:  m.migrateTo1,","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/configmigrate/migrator.go#L78-L114","documentation":"validateVersion rejects a migration where the requested target schema version is lower than the config's current version — i.e. a downgrade. Only forward migrations are supported.","triggerScenarios":"Calling Migrate with target < current, e.g. Migrate(body, 15) when the file already has schema_version: 29.","commonSituations":"Attempting to roll a config back to work with an older tool, accidentally swapping the version arguments, or test code passing the versions in the wrong order.","solutions":["Pass target >= current (normally LastSchemaVersion)","To support an older binary, regenerate a fresh config instead of downgrading","Fix argument order if the versions were swapped"],"exampleFix":"// before\nnewBody, _, err := configmigrate.Migrate(ctx, body, 15) // current is 29\n\n// after\nnewBody, _, err := configmigrate.Migrate(ctx, body, configmigrate.LastSchemaVersion)","handlingStrategy":"validation","validationCode":"if target < current { /* don't call Migrate; downgrades unsupported */ }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"lower than current\") { /* fix argument order or accept current version */ }","preventionTips":["Assert target >= current in wrapper functions","Remember: migrations are one-way; regenerate configs instead of downgrading"],"tags":["config","migration","version","downgrade"],"backgroundTag":"schema-version-mismatch","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}