{"record":{"id":"d88c8bce1d7a28f3","repo":"kopia/kopia","slug":"repository-will-remain-locked-until-index-differen","errorCode":null,"errorMessage":"repository will remain locked until index differences are resolved","messagePattern":"repository will remain locked until index differences are resolved","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command_repository_upgrade.go","lineNumber":196,"sourceCode":"\n\t\tmsgs = append(msgs, fmt.Sprintf(\"lop-sided index entries for contentID %q at blob %q\", contentID, iep1.PackBlobID))\n\t}\n\n\t// no msgs means the check passed without finding anything wrong\n\tif len(msgs) == 0 {\n\t\tlog(ctx).Info(\"index validation succeeded\")\n\t\treturn nil\n\t}\n\n\t// otherwise there's a problem somewhere ... log the problems\n\tlog(ctx).Error(\"inconsistencies found in migrated index:\")\n\n\tfor _, m := range msgs {\n\t\tlog(ctx).Error(m)\n\t}\n\n\t// and return an error that states something's wrong.\n\treturn errors.Wrap(err, \"repository will remain locked until index differences are resolved\")\n}\n\n// CheckIndexInfo compare two index infos.  If a mismatch exists, return an error with diagnostic information.\nfunc CheckIndexInfo(i0, i1 content.Info) []string {\n\tvar q []string\n\n\tswitch {\n\tcase i0.FormatVersion != i1.FormatVersion:\n\t\tq = append(q, fmt.Sprintf(\"mismatched FormatVersions: %v %v\", i0.FormatVersion, i1.FormatVersion))\n\tcase i0.OriginalLength != i1.OriginalLength:\n\t\tq = append(q, fmt.Sprintf(\"mismatched OriginalLengths: %v %v\", i0.OriginalLength, i1.OriginalLength))\n\tcase i0.PackBlobID != i1.PackBlobID:\n\t\tq = append(q, fmt.Sprintf(\"mismatched PackBlobIDs: %v %v\", i0.PackBlobID, i1.PackBlobID))\n\tcase i0.PackedLength != i1.PackedLength:\n\t\tq = append(q, fmt.Sprintf(\"mismatched PackedLengths: %v %v\", i0.PackedLength, i1.PackedLength))\n\tcase i0.PackOffset != i1.PackOffset:\n\t\tq = append(q, fmt.Sprintf(\"mismatched PackOffsets: %v %v\", i0.PackOffset, i1.PackOffset))\n\tcase i0.EncryptionKeyID != i1.EncryptionKeyID:","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/cli/command_repository_upgrade.go#L178-L214","documentation":"During `kopia repository upgrade`, validateAction logs all mismatch messages produced by CheckIndexInfo and wraps the underlying validation error with 'repository will remain locked until index differences are resolved'. The upgrade validation phase detected index differences (e.g. undeleted index blobs or pending epoch work) that make it unsafe to proceed, so the command aborts while the repository upgrade lock stays in place.","triggerScenarios":"Running `kopia repository upgrade` (or `repository upgrade validate`) when CheckIndexInfo finds differences between index infos: direct-index blobs that should have been deleted, or mutable-index contents not yet migrated/compacted. validateAction returns errors.Wrap(err, ...) at cli/command_repository_upgrade.go:196.","commonSituations":"Upgrading to the epoch manager while some connected clients still wrote recently (index blobs not yet aged out); running the upgrade too soon after the io-drain window without all clients having flushed; interrupted previous upgrades leaving index blobs behind.","solutions":["Wait for the required index-blob deletion delay (or run `kopia index optimize` / restart with all clients connected) so old index blobs get deleted, then retry the upgrade validate step.","Check the logged mismatch messages above the error (CheckIndexInfo diagnostics) and address each listed index difference.","Ensure all kopia clients are upgraded/connected and drained so no new index blobs appear during validation.","As a last resort, revoke the lock with `kopia repository upgrade force-revert` (--force) and restart the upgrade after cleanup."],"exampleFix":"// before\nkopia repository upgrade --io-drain-timeout=5s\n// after: wait for index blobs to become deletable and re-run validation\nkopia index optimize\nkopia repository upgrade --io-drain-timeout=30m --advance-notice=24h","handlingStrategy":"validation","validationCode":"// before upgrading, ensure index differences are resolved\nconst mismatches = await runKopia(['repository', 'upgrade', 'validate', '--dry-run']);\nif (mismatches.exitCode !== 0) {\n  throw new Error(`Index differences remain: ${mismatches.stderr}. Run 'kopia index optimize' and retry.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await upgradeRepository();\n} catch (e) {\n  if (/index differences are resolved/.test(e.message)) {\n    await runKopia(['index', 'optimize']);\n    await retry(upgradeRepository, { retries: 1 });\n  }\n}","preventionTips":["Run `kopia repository upgrade validate` first and resolve every reported mismatch.","Ensure all clients are connected and current before starting the upgrade.","Allow the index-blob deletion delay to elapse before upgrading to epoch format."],"tags":["repository-upgrade","index","kopia","cli"],"backgroundTag":"invalid-state-transition","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}