diff --git a/lib/util/cache/repository/common.ts b/lib/util/cache/repository/common.ts
index b35b57d7a635fa7929a20fd824539cc21fd37719..2846c28ceea852e321f175a3bc0d57842e2015d6 100644
--- a/lib/util/cache/repository/common.ts
+++ b/lib/util/cache/repository/common.ts
@@ -1,70 +1,2 @@
-import is from '@sindresorhus/is';
-import type {
-  RepoCacheRecordV10,
-  RepoCacheRecordV11,
-  RepoCacheRecordV12,
-  RepoCacheRecordV13,
-} from './types';
-
 // Increment this whenever there could be incompatibilities between old and new cache structure
 export const CACHE_REVISION = 13;
-
-export function isValidRev10(
-  input: unknown,
-  repo?: string
-): input is RepoCacheRecordV10 {
-  return (
-    is.plainObject(input) &&
-    is.safeInteger(input.revision) &&
-    input.revision === 10 &&
-    is.string(input.repository) &&
-    (!repo || repo === input.repository)
-  );
-}
-
-export function isValidRev11(
-  input: unknown,
-  repo?: string
-): input is RepoCacheRecordV11 {
-  return (
-    is.plainObject(input) &&
-    is.safeInteger(input.revision) &&
-    input.revision === 11 &&
-    is.string(input.repository) &&
-    is.plainObject(input.data) &&
-    (!repo || repo === input.repository)
-  );
-}
-
-function isValidRev12Shape(
-  input: unknown,
-  repo?: string
-): input is RepoCacheRecordV12 {
-  return (
-    is.plainObject(input) &&
-    is.safeInteger(input.revision) &&
-    is.string(input.repository) &&
-    is.string(input.payload) &&
-    is.string(input.hash)
-  );
-}
-
-export function isValidRev12(
-  input: unknown,
-  repo?: string
-): input is RepoCacheRecordV12 {
-  return (
-    isValidRev12Shape(input, repo) &&
-    input.revision === 12 &&
-    (!repo || repo === input.repository)
-  );
-}
-
-export function isValidRev13(input: unknown): input is RepoCacheRecordV13 {
-  return (
-    is.plainObject(input) &&
-    is.string(input.fingerprint) &&
-    isValidRev12Shape(input) &&
-    input.revision === 13
-  );
-}
diff --git a/lib/util/cache/repository/impl/base.ts b/lib/util/cache/repository/impl/base.ts
index 1b4c080a44b3f5e19123d88b5f41349ad1c15c1c..f234f11d20525341265abf0f4ca901c598fe513c 100644
--- a/lib/util/cache/repository/impl/base.ts
+++ b/lib/util/cache/repository/impl/base.ts
@@ -4,23 +4,11 @@ import is from '@sindresorhus/is';
 import hasha from 'hasha';
 import { GlobalConfig } from '../../../../config/global';
 import { logger } from '../../../../logger';
+import * as schema from '../../../schema';
 import { safeStringify } from '../../../stringify';
-import {
-  CACHE_REVISION,
-  isValidRev10,
-  isValidRev11,
-  isValidRev12,
-  isValidRev13,
-} from '../common';
-import type {
-  RepoCache,
-  RepoCacheData,
-  RepoCacheRecord,
-  RepoCacheRecordV10,
-  RepoCacheRecordV11,
-  RepoCacheRecordV12,
-  RepoCacheRecordV13,
-} from '../types';
+import { CACHE_REVISION } from '../common';
+import { RepoCacheRecord, RepoCacheV13 } from '../schemas';
+import type { RepoCache, RepoCacheData } from '../types';
 
 const compress = promisify(zlib.brotliCompress);
 const decompress = promisify(zlib.brotliDecompress);
@@ -39,17 +27,11 @@ export abstract class RepoCacheBase implements RepoCache {
 
   protected abstract write(data: RepoCacheRecord): Promise<void>;
 
-  private restoreFromRev10(oldCache: RepoCacheRecordV10): void {
-    delete oldCache.repository;
-    delete oldCache.revision;
-    this.data = oldCache;
-  }
-
-  private restoreFromRev11(oldCache: RepoCacheRecordV11): void {
-    this.data = oldCache.data;
-  }
-
-  private async restoreFromRev12(oldCache: RepoCacheRecordV12): Promise<void> {
+  private async restore(oldCache: RepoCacheRecord): Promise<void> {
+    if (oldCache.fingerprint !== this.fingerprint) {
+      logger.debug('Repository cache fingerprint is invalid');
+      return;
+    }
     const compressed = Buffer.from(oldCache.payload, 'base64');
     const uncompressed = await decompress(compressed);
     const jsonStr = uncompressed.toString('utf8');
@@ -57,14 +39,6 @@ export abstract class RepoCacheBase implements RepoCache {
     this.oldHash = oldCache.hash;
   }
 
-  private async restoreFromRev13(oldCache: RepoCacheRecordV13): Promise<void> {
-    if (oldCache.fingerprint !== this.fingerprint) {
-      logger.debug('Repository cache fingerprint is invalid');
-      return;
-    }
-    await this.restoreFromRev12(oldCache);
-  }
-
   async load(): Promise<void> {
     try {
       const rawOldCache = await this.read();
@@ -76,30 +50,12 @@ export abstract class RepoCacheBase implements RepoCache {
       }
       const oldCache = JSON.parse(rawOldCache) as unknown;
 
-      if (isValidRev13(oldCache)) {
-        await this.restoreFromRev13(oldCache);
+      if (schema.match(RepoCacheV13, oldCache)) {
+        await this.restore(oldCache);
         logger.debug('Repository cache is restored from revision 13');
         return;
       }
 
-      if (isValidRev12(oldCache, this.repository)) {
-        await this.restoreFromRev12(oldCache);
-        logger.debug('Repository cache is restored from revision 12');
-        return;
-      }
-
-      if (isValidRev11(oldCache, this.repository)) {
-        this.restoreFromRev11(oldCache);
-        logger.debug('Repository cache is restored from revision 11');
-        return;
-      }
-
-      if (isValidRev10(oldCache, this.repository)) {
-        this.restoreFromRev10(oldCache);
-        logger.debug('Repository cache is restored from revision 10');
-        return;
-      }
-
       logger.debug('Repository cache is invalid');
     } catch (err) {
       logger.debug({ err }, 'Error reading repository cache');
diff --git a/lib/util/cache/repository/impl/local.spec.ts b/lib/util/cache/repository/impl/local.spec.ts
index 7f0e7a9496b364633fbd862afef724744a27b0b5..1b17bf89aac20028ad529f2c04b92c2dd5b2b00d 100644
--- a/lib/util/cache/repository/impl/local.spec.ts
+++ b/lib/util/cache/repository/impl/local.spec.ts
@@ -5,7 +5,8 @@ import { fs } from '../../../../../test/util';
 import { GlobalConfig } from '../../../../config/global';
 import { logger } from '../../../../logger';
 import { CACHE_REVISION } from '../common';
-import type { RepoCacheData, RepoCacheRecord } from '../types';
+import type { RepoCacheRecord } from '../schemas';
+import type { RepoCacheData } from '../types';
 import { CacheFactory } from './cache-factory';
 import { RepoCacheLocal } from './local';
 
@@ -109,102 +110,6 @@ describe('util/cache/repository/impl/local', () => {
     expect(cache2.getData()).toBeEmpty();
   });
 
-  it('migrates revision from 10 to 13', async () => {
-    fs.readCacheFile.mockResolvedValue(
-      JSON.stringify({
-        revision: 10,
-        repository: 'some/repo',
-        semanticCommits: 'enabled',
-      })
-    );
-    const localRepoCache = CacheFactory.get(
-      'some/repo',
-      '0123456789abcdef',
-      'local'
-    );
-
-    await localRepoCache.load();
-    await localRepoCache.save();
-
-    const cacheRecord = await createCacheRecord({ semanticCommits: 'enabled' });
-    expect(fs.outputCacheFile).toHaveBeenCalledWith(
-      '/tmp/cache/renovate/repository/github/some/repo.json',
-      JSON.stringify(cacheRecord)
-    );
-  });
-
-  it('migrates revision from 11 to 13', async () => {
-    fs.readCacheFile.mockResolvedValue(
-      JSON.stringify({
-        revision: 11,
-        repository: 'some/repo',
-        data: { semanticCommits: 'enabled' },
-      })
-    );
-    const localRepoCache = CacheFactory.get(
-      'some/repo',
-      '0123456789abcdef',
-      'local'
-    );
-
-    await localRepoCache.load();
-    await localRepoCache.save();
-
-    const cacheRecord = await createCacheRecord({ semanticCommits: 'enabled' });
-    expect(fs.outputCacheFile).toHaveBeenCalledWith(
-      '/tmp/cache/renovate/repository/github/some/repo.json',
-      JSON.stringify(cacheRecord)
-    );
-  });
-
-  it('migrates revision from 12 to 13', async () => {
-    const { repository, payload, hash } = await createCacheRecord({
-      semanticCommits: 'enabled',
-    });
-
-    fs.readCacheFile.mockResolvedValue(
-      JSON.stringify({ revision: 12, repository, payload, hash })
-    );
-    const localRepoCache = CacheFactory.get(
-      'some/repo',
-      '0123456789abcdef',
-      'local'
-    );
-
-    await localRepoCache.load();
-    const data = localRepoCache.getData();
-    data.semanticCommits = 'disabled';
-    await localRepoCache.save();
-
-    expect(fs.outputCacheFile).toHaveBeenCalledWith(
-      '/tmp/cache/renovate/repository/github/some/repo.json',
-      JSON.stringify(
-        await createCacheRecord({
-          semanticCommits: 'disabled',
-        })
-      )
-    );
-  });
-
-  it('does not migrate from older revisions to 11', async () => {
-    fs.readCacheFile.mockResolvedValueOnce(
-      JSON.stringify({
-        revision: 9,
-        repository: 'some/repo',
-        semanticCommits: 'enabled',
-      })
-    );
-
-    const localRepoCache = CacheFactory.get(
-      'some/repo',
-      '0123456789abcdef',
-      'local'
-    );
-    await localRepoCache.load();
-
-    expect(localRepoCache.getData()).toBeEmpty();
-  });
-
   it('handles invalid data', async () => {
     fs.readCacheFile.mockResolvedValue(JSON.stringify({ foo: 'bar' }));
     const localRepoCache = CacheFactory.get(
diff --git a/lib/util/cache/repository/impl/local.ts b/lib/util/cache/repository/impl/local.ts
index 306b891c4cf44885cc74e38cb80bfdb6ed5cf709..ffed379566bf62765690feb383976bd9d115a130 100644
--- a/lib/util/cache/repository/impl/local.ts
+++ b/lib/util/cache/repository/impl/local.ts
@@ -2,7 +2,7 @@ import upath from 'upath';
 import { GlobalConfig } from '../../../../config/global';
 import { logger } from '../../../../logger';
 import { cachePathExists, outputCacheFile, readCacheFile } from '../../../fs';
-import type { RepoCacheRecord } from '../types';
+import type { RepoCacheRecord } from '../schemas';
 import { RepoCacheBase } from './base';
 
 export class RepoCacheLocal extends RepoCacheBase {
diff --git a/lib/util/cache/repository/impl/s3.spec.ts b/lib/util/cache/repository/impl/s3.spec.ts
index 48b894d5ddc3f7ddea91a89cf2f20f949889f7be..cfb276a6f38b1323a5acfe9d04380b2dfa6e4052 100644
--- a/lib/util/cache/repository/impl/s3.spec.ts
+++ b/lib/util/cache/repository/impl/s3.spec.ts
@@ -12,7 +12,7 @@ import { partial } from '../../../../../test/util';
 import { GlobalConfig } from '../../../../config/global';
 import { logger } from '../../../../logger';
 import { parseS3Url } from '../../../s3';
-import type { RepoCacheRecord } from '../types';
+import type { RepoCacheRecord } from '../schemas';
 import { CacheFactory } from './cache-factory';
 import { RepoCacheS3 } from './s3';
 
diff --git a/lib/util/cache/repository/impl/s3.ts b/lib/util/cache/repository/impl/s3.ts
index c1d8f02c7fa40c66c3dd5c1d2aa0c33f4abe25b3..da57ba094a7a168ec74c60631939b7293642db89 100644
--- a/lib/util/cache/repository/impl/s3.ts
+++ b/lib/util/cache/repository/impl/s3.ts
@@ -8,7 +8,7 @@ import {
 import { logger } from '../../../../logger';
 import { getS3Client, parseS3Url } from '../../../s3';
 import { streamToString } from '../../../streams';
-import type { RepoCacheRecord } from '../types';
+import type { RepoCacheRecord } from '../schemas';
 import { RepoCacheBase } from './base';
 
 export class RepoCacheS3 extends RepoCacheBase {
diff --git a/lib/util/cache/repository/schemas.ts b/lib/util/cache/repository/schemas.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61af6926e069de5623990f67809e001147bc04bd
--- /dev/null
+++ b/lib/util/cache/repository/schemas.ts
@@ -0,0 +1,13 @@
+import { z } from 'zod';
+
+export const RepoCacheV13 = z
+  .object({
+    repository: z.string().min(1),
+    revision: z.number().refine((v) => v === 13),
+    payload: z.string().min(1),
+    hash: z.string().min(1),
+    fingerprint: z.string().min(1),
+  })
+  .strict();
+
+export type RepoCacheRecord = z.infer<typeof RepoCacheV13>;
diff --git a/lib/util/cache/repository/types.ts b/lib/util/cache/repository/types.ts
index e11a5c69315f39762e3acc27ced03ef4bf0ffebc..64d8a1d63fe4a997d797a3da80b4513e81fc73e2 100644
--- a/lib/util/cache/repository/types.ts
+++ b/lib/util/cache/repository/types.ts
@@ -75,30 +75,6 @@ export interface RepoCacheData {
   prComments?: Record<number, Record<string, string>>;
 }
 
-export interface RepoCacheRecordV10 extends RepoCacheData {
-  repository?: string;
-  revision?: number;
-}
-
-export interface RepoCacheRecordV11 {
-  repository: string;
-  revision: number;
-  data: RepoCacheData;
-}
-
-export interface RepoCacheRecordV12 {
-  repository: string;
-  revision: number;
-  payload: string;
-  hash: string;
-}
-
-export interface RepoCacheRecordV13 extends RepoCacheRecordV12 {
-  fingerprint: string;
-}
-
-export type RepoCacheRecord = RepoCacheRecordV13;
-
 export interface RepoCache {
   load(): Promise<void>;
   save(): Promise<void>;