diff --git a/lib/config/presets/gitea/index.ts b/lib/config/presets/gitea/index.ts
index 66eef53360a26543ba4a0e98bba8c2f3a605e143..adb71c599337d4c8286bae809d5312882bc6b8a2 100644
--- a/lib/config/presets/gitea/index.ts
+++ b/lib/config/presets/gitea/index.ts
@@ -29,7 +29,7 @@ export async function fetchJSONFile(
   }
 
   // TODO: null check #22198
-  return parsePreset(fromBase64(res.content!));
+  return parsePreset(fromBase64(res.content!), fileName);
 }
 
 export function getPresetFromEndpoint(
diff --git a/lib/config/presets/github/index.ts b/lib/config/presets/github/index.ts
index da087ae1c4582e6851425bb72239937c05556f44..4d1584b0d8e6e972ad4d9d604821ced0a6985156 100644
--- a/lib/config/presets/github/index.ts
+++ b/lib/config/presets/github/index.ts
@@ -34,7 +34,7 @@ export async function fetchJSONFile(
     throw new Error(PRESET_DEP_NOT_FOUND);
   }
 
-  return parsePreset(fromBase64(res.body.content));
+  return parsePreset(fromBase64(res.body.content), fileName);
 }
 
 export function getPresetFromEndpoint(
diff --git a/lib/config/presets/gitlab/index.ts b/lib/config/presets/gitlab/index.ts
index b1f4071ccd9923bb2b184445c77f90995fd695a7..6c3c336bb3a01e723a8e33bd82d9beb045c8b088 100644
--- a/lib/config/presets/gitlab/index.ts
+++ b/lib/config/presets/gitlab/index.ts
@@ -52,7 +52,7 @@ export async function fetchJSONFile(
     throw new Error(PRESET_DEP_NOT_FOUND);
   }
 
-  return parsePreset(res.body);
+  return parsePreset(res.body, fileName);
 }
 
 export function getPresetFromEndpoint(
diff --git a/lib/config/presets/local/common.ts b/lib/config/presets/local/common.ts
index bc955972483577cca6a03b01e3a21a837151c5ed..00e11f8517f553be8380e35634cd04ad44b1183b 100644
--- a/lib/config/presets/local/common.ts
+++ b/lib/config/presets/local/common.ts
@@ -29,7 +29,7 @@ export async function fetchJSONFile(
     throw new Error(PRESET_DEP_NOT_FOUND);
   }
 
-  return parsePreset(raw);
+  return parsePreset(raw, fileName);
 }
 
 export function getPresetFromEndpoint(
diff --git a/lib/config/presets/util.ts b/lib/config/presets/util.ts
index f7a22505a98a0cd9a68ff045a6094dbf007af992..7b2f166886ff5a7cf0ede1d7b77d4ee26a0235f9 100644
--- a/lib/config/presets/util.ts
+++ b/lib/config/presets/util.ts
@@ -1,5 +1,5 @@
-import JSON5 from 'json5';
 import { logger } from '../../logger';
+import { parseJson } from '../../util/common';
 import { regEx } from '../../util/regex';
 import { ensureTrailingSlash } from '../../util/url';
 import type { FetchPresetConfig, Preset } from './types';
@@ -87,9 +87,9 @@ export async function fetchPreset({
   return jsonContent;
 }
 
-export function parsePreset(content: string): Preset {
+export function parsePreset(content: string, fileName: string): Preset {
   try {
-    return JSON5.parse(content);
+    return parseJson(content, fileName) as Preset;
   } catch (err) {
     throw new Error(PRESET_INVALID_JSON);
   }
diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts
index f3c869b7b1cec80287e032a29d17a5a51188b9e3..e367d9c1423b7df50bcdcb28d436522c496deecc 100644
--- a/lib/modules/platform/azure/index.ts
+++ b/lib/modules/platform/azure/index.ts
@@ -9,7 +9,6 @@ import {
   GitVersionDescriptor,
   PullRequestStatus,
 } from 'azure-devops-node-api/interfaces/GitInterfaces.js';
-import JSON5 from 'json5';
 import {
   REPOSITORY_ARCHIVED,
   REPOSITORY_EMPTY,
@@ -18,6 +17,7 @@ import {
 import { logger } from '../../../logger';
 import type { BranchStatus } from '../../../types';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { regEx } from '../../../util/regex';
@@ -182,7 +182,7 @@ export async function getJsonFile(
   branchOrTag?: string
 ): Promise<any> {
   const raw = await getRawFile(fileName, repoName, branchOrTag);
-  return raw ? JSON5.parse(raw) : null;
+  return parseJson(raw, fileName);
 }
 
 export async function initRepo({
diff --git a/lib/modules/platform/bitbucket-server/index.ts b/lib/modules/platform/bitbucket-server/index.ts
index eea3911b79d835993dcc6e6e2b23865ff3e17357..eaea2c62f02e7e1bcfe18b734e58e86d33c86626 100644
--- a/lib/modules/platform/bitbucket-server/index.ts
+++ b/lib/modules/platform/bitbucket-server/index.ts
@@ -1,5 +1,4 @@
 import { setTimeout } from 'timers/promises';
-import JSON5 from 'json5';
 import type { PartialDeep } from 'type-fest';
 import {
   REPOSITORY_CHANGED,
@@ -9,6 +8,7 @@ import {
 import { logger } from '../../../logger';
 import type { BranchStatus } from '../../../types';
 import type { FileData } from '../../../types/platform/bitbucket-server';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import { deleteBranch } from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
@@ -146,8 +146,8 @@ export async function getJsonFile(
   branchOrTag?: string
 ): Promise<any> {
   // TODO #22198
-  const raw = (await getRawFile(fileName, repoName, branchOrTag)) as string;
-  return JSON5.parse(raw);
+  const raw = await getRawFile(fileName, repoName, branchOrTag);
+  return parseJson(raw, fileName);
 }
 
 // Initialize Bitbucket Server by getting base branch
diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts
index 96a23aa49c3484ac9fe35bfed0118892fe51c9e6..b1b918ee20ed12a9fa5640e45af94860c24d384d 100644
--- a/lib/modules/platform/bitbucket/index.ts
+++ b/lib/modules/platform/bitbucket/index.ts
@@ -1,9 +1,9 @@
 import URL from 'node:url';
 import is from '@sindresorhus/is';
-import JSON5 from 'json5';
 import { REPOSITORY_NOT_FOUND } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
 import type { BranchStatus } from '../../../types';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { BitbucketHttp, setBaseUrl } from '../../../util/http/bitbucket';
@@ -158,8 +158,8 @@ export async function getJsonFile(
   branchOrTag?: string
 ): Promise<any> {
   // TODO #22198
-  const raw = (await getRawFile(fileName, repoName, branchOrTag)) as string;
-  return JSON5.parse(raw);
+  const raw = await getRawFile(fileName, repoName, branchOrTag);
+  return parseJson(raw, fileName);
 }
 
 // Initialize bitbucket by getting base branch and SHA
diff --git a/lib/modules/platform/codecommit/index.ts b/lib/modules/platform/codecommit/index.ts
index cc6b69d9d7ac20379d21ba71eeeaf22bda025754..7b7ddcc449396e048cbb2af3973df0535fd790e2 100644
--- a/lib/modules/platform/codecommit/index.ts
+++ b/lib/modules/platform/codecommit/index.ts
@@ -4,8 +4,6 @@ import {
   ListRepositoriesOutput,
   PullRequestStatusEnum,
 } from '@aws-sdk/client-codecommit';
-import JSON5 from 'json5';
-
 import {
   PLATFORM_BAD_CREDENTIALS,
   REPOSITORY_EMPTY,
@@ -14,6 +12,7 @@ import {
 import { logger } from '../../../logger';
 import type { BranchStatus, PrState } from '../../../types';
 import { coerceArray } from '../../../util/array';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import { regEx } from '../../../util/regex';
 import { sanitize } from '../../../util/sanitize';
@@ -329,7 +328,7 @@ export async function getJsonFile(
   branchOrTag?: string
 ): Promise<any> {
   const raw = await getRawFile(fileName, repoName, branchOrTag);
-  return raw ? JSON5.parse(raw) : null;
+  return parseJson(raw, fileName);
 }
 
 export async function getRawFile(
diff --git a/lib/modules/platform/gitea/index.ts b/lib/modules/platform/gitea/index.ts
index 79e80177f13166e48b271bb411e59d0b0a2fbcb7..89729341863b109a58df461cae26c51644ad8e43 100644
--- a/lib/modules/platform/gitea/index.ts
+++ b/lib/modules/platform/gitea/index.ts
@@ -1,5 +1,4 @@
 import is from '@sindresorhus/is';
-import JSON5 from 'json5';
 import semver from 'semver';
 import {
   REPOSITORY_ACCESS_FORBIDDEN,
@@ -11,6 +10,7 @@ import {
 } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
 import type { BranchStatus } from '../../../types';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import { setBaseUrl } from '../../../util/http/gitea';
 import { sanitize } from '../../../util/sanitize';
@@ -256,8 +256,8 @@ const platform: Platform = {
     branchOrTag?: string
   ): Promise<any> {
     // TODO #22198
-    const raw = (await platform.getRawFile(fileName, repoName, branchOrTag))!;
-    return JSON5.parse(raw);
+    const raw = await platform.getRawFile(fileName, repoName, branchOrTag);
+    return parseJson(raw, fileName);
   },
 
   async initRepo({
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 1ad9921a51d3a6ee3c8199b6fad01434afaa6c52..196168cbc234bce09d5ee2bf24bd9d03f55d701e 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -3430,6 +3430,17 @@ describe('modules/platform/github/index', () => {
   });
 
   describe('getJsonFile()', () => {
+    it('returns null', async () => {
+      const scope = httpMock.scope(githubApiHost);
+      initRepoMock(scope, 'some/repo');
+      await github.initRepo({ repository: 'some/repo' });
+      scope.get('/repos/some/repo/contents/file.json').reply(200, {
+        content: '',
+      });
+      const res = await github.getJsonFile('file.json');
+      expect(res).toBeNull();
+    });
+
     it('returns file content', async () => {
       const data = { foo: 'bar' };
       const scope = httpMock.scope(githubApiHost);
diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts
index bdc39b5457ca989d9222113835957ffd85b6e1c3..0df999996ff009f027a8931f6b9e8f4567440562 100644
--- a/lib/modules/platform/github/index.ts
+++ b/lib/modules/platform/github/index.ts
@@ -1,7 +1,6 @@
 import URL from 'node:url';
 import { setTimeout } from 'timers/promises';
 import is from '@sindresorhus/is';
-import JSON5 from 'json5';
 import { DateTime } from 'luxon';
 import semver from 'semver';
 import { GlobalConfig } from '../../../config/global';
@@ -25,6 +24,7 @@ import type { BranchStatus, VulnerabilityAlert } from '../../../types';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import { isGithubFineGrainedPersonalAccessToken } from '../../../util/check-token';
 import { coerceToNull } from '../../../util/coerce';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import { listCommitTree, pushCommitToRenovateRef } from '../../../util/git';
 import type {
@@ -331,9 +331,8 @@ export async function getJsonFile(
   repoName?: string,
   branchOrTag?: string
 ): Promise<any> {
-  // TODO #22198
-  const raw = (await getRawFile(fileName, repoName, branchOrTag)) as string;
-  return JSON5.parse(raw);
+  const raw = await getRawFile(fileName, repoName, branchOrTag);
+  return parseJson(raw, fileName);
 }
 
 export async function listForks(
diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts
index 5f3afefd291ff26b96274ecd9fc5828b214dd2e6..fadc5178b08aa3ff0530f2dc2466a53952e745c6 100644
--- a/lib/modules/platform/gitlab/index.spec.ts
+++ b/lib/modules/platform/gitlab/index.spec.ts
@@ -2641,6 +2641,19 @@ These updates have all been created already. Click a checkbox below to force a r
   });
 
   describe('getJsonFile()', () => {
+    it('returns null', async () => {
+      const scope = await initRepo();
+      scope
+        .get(
+          '/api/v4/projects/some%2Frepo/repository/files/dir%2Ffile.json?ref=HEAD'
+        )
+        .reply(200, {
+          content: '',
+        });
+      const res = await gitlab.getJsonFile('dir/file.json');
+      expect(res).toBeNull();
+    });
+
     it('returns file content', async () => {
       const data = { foo: 'bar' };
       const scope = await initRepo();
diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts
index 27567a0f00ca249b37f9d19956143d870879db86..58e8c6bf9ffd07fea4514ed311a40945dfe60ebb 100644
--- a/lib/modules/platform/gitlab/index.ts
+++ b/lib/modules/platform/gitlab/index.ts
@@ -1,7 +1,6 @@
 import URL from 'node:url';
 import { setTimeout } from 'timers/promises';
 import is from '@sindresorhus/is';
-import JSON5 from 'json5';
 import pMap from 'p-map';
 import semver from 'semver';
 import {
@@ -19,6 +18,7 @@ import {
 import { logger } from '../../../logger';
 import type { BranchStatus } from '../../../types';
 import { coerceArray } from '../../../util/array';
+import { parseJson } from '../../../util/common';
 import * as git from '../../../util/git';
 import * as hostRules from '../../../util/host-rules';
 import { setBaseUrl } from '../../../util/http/gitlab';
@@ -231,9 +231,8 @@ export async function getJsonFile(
   repoName?: string,
   branchOrTag?: string
 ): Promise<any> {
-  // TODO #22198
-  const raw = (await getRawFile(fileName, repoName, branchOrTag)) as string;
-  return JSON5.parse(raw);
+  const raw = await getRawFile(fileName, repoName, branchOrTag);
+  return parseJson(raw, fileName);
 }
 
 function getRepoUrl(
diff --git a/lib/util/common.spec.ts b/lib/util/common.spec.ts
index 8505ad27447467d948fedfb7c85387b18dce81c8..0b053aff055444ccbeb3738043531bd5d162e632 100644
--- a/lib/util/common.spec.ts
+++ b/lib/util/common.spec.ts
@@ -1,6 +1,33 @@
-import { detectPlatform } from './common';
+import { logger } from '../../test/util';
+import { detectPlatform, parseJson } from './common';
 import * as hostRules from './host-rules';
 
+const validJsonString = `
+{
+  "name": "John Doe",
+  "age": 30,
+  "city": "New York"
+}
+`;
+const invalidJsonString = `
+{
+  "name": "Alice",
+  "age": 25,
+  "city": "Los Angeles",
+  "hobbies": ["Reading", "Running", "Cooking"]
+  "isStudent": true
+}
+`;
+const onlyJson5parsableString = `
+{
+  name: "Bob",
+  age: 35,
+  city: 'San Francisco',
+  // This is a comment
+  "isMarried": false,
+}
+`;
+
 describe('util/common', () => {
   beforeEach(() => hostRules.clear());
 
@@ -60,4 +87,35 @@ describe('util/common', () => {
       expect(detectPlatform('https://f.example.com/chalk/chalk')).toBeNull();
     });
   });
+
+  describe('parseJson', () => {
+    it('returns null', () => {
+      expect(parseJson(null, 'renovate.json')).toBeNull();
+    });
+
+    it('returns parsed json', () => {
+      expect(parseJson(validJsonString, 'renovate.json')).toEqual({
+        name: 'John Doe',
+        age: 30,
+        city: 'New York',
+      });
+    });
+
+    it('throws error for invalid json', () => {
+      expect(() => parseJson(invalidJsonString, 'renovate.json')).toThrow();
+    });
+
+    it('catches and warns if content parsing faield with JSON.parse but not with JSON5.parse', () => {
+      expect(parseJson(onlyJson5parsableString, 'renovate.json')).toEqual({
+        name: 'Bob',
+        age: 35,
+        city: 'San Francisco',
+        isMarried: false,
+      });
+      expect(logger.logger.warn).toHaveBeenCalledWith(
+        { context: 'renovate.json' },
+        'File contents are invalid JSON but parse using JSON5. Support for this will be removed in a future release so please change to a support .json5 file name or ensure correct JSON syntax.'
+      );
+    });
+  });
 });
diff --git a/lib/util/common.ts b/lib/util/common.ts
index df7db5ab4ab45fa369583343bd3c52540732bc71..d7348a763c2673e89e8893c3ee2004e5d8f74919 100644
--- a/lib/util/common.ts
+++ b/lib/util/common.ts
@@ -1,9 +1,11 @@
+import JSON5 from 'json5';
 import {
   BITBUCKET_API_USING_HOST_TYPES,
   GITEA_API_USING_HOST_TYPES,
   GITHUB_API_USING_HOST_TYPES,
   GITLAB_API_USING_HOST_TYPES,
 } from '../constants';
+import { logger } from '../logger';
 import * as hostRules from './host-rules';
 import { parseUrl } from './url';
 
@@ -59,3 +61,32 @@ export function detectPlatform(
 
   return null;
 }
+
+export function parseJson(content: string | null, filename: string): unknown {
+  if (!content) {
+    return null;
+  }
+
+  return filename.endsWith('.json5')
+    ? JSON5.parse(content)
+    : parseJsonWithFallback(content, filename);
+}
+
+export function parseJsonWithFallback(
+  content: string,
+  context: string
+): unknown {
+  let parsedJson: unknown;
+
+  try {
+    parsedJson = JSON.parse(content);
+  } catch (err) {
+    parsedJson = JSON5.parse(content);
+    logger.warn(
+      { context },
+      'File contents are invalid JSON but parse using JSON5. Support for this will be removed in a future release so please change to a support .json5 file name or ensure correct JSON syntax.'
+    );
+  }
+
+  return parsedJson;
+}
diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts
index 4ccdca5f392bb64515c08beada1431bdfeb56796..679fdbb0c22f1a82933f4826a837ffd15ce370ee 100644
--- a/lib/workers/global/config/parse/file.ts
+++ b/lib/workers/global/config/parse/file.ts
@@ -6,6 +6,7 @@ import upath from 'upath';
 import { migrateConfig } from '../../../../config/migration';
 import type { AllConfig, RenovateConfig } from '../../../../config/types';
 import { logger } from '../../../../logger';
+import { parseJson } from '../../../../util/common';
 import { readSystemFile } from '../../../../util/fs';
 
 export async function getParsedContent(file: string): Promise<RenovateConfig> {
@@ -20,7 +21,10 @@ export async function getParsedContent(file: string): Promise<RenovateConfig> {
       }) as RenovateConfig;
     case '.json5':
     case '.json':
-      return JSON5.parse(await readSystemFile(file, 'utf8'));
+      return parseJson(
+        await readSystemFile(file, 'utf8'),
+        file
+      ) as RenovateConfig;
     case '.js': {
       const tmpConfig = await import(file);
       let config = tmpConfig.default
diff --git a/lib/workers/repository/init/merge.ts b/lib/workers/repository/init/merge.ts
index 7c4b2b0b81ac279ac746a3fb6690383c1e7bdddf..c8a33f23946f4096566e85bed56ef514d091c28e 100644
--- a/lib/workers/repository/init/merge.ts
+++ b/lib/workers/repository/init/merge.ts
@@ -20,6 +20,7 @@ import { platform } from '../../../modules/platform';
 import { scm } from '../../../modules/platform/scm';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import { getCache } from '../../../util/cache/repository';
+import { parseJson } from '../../../util/common';
 import { readLocalFile } from '../../../util/fs';
 import * as hostRules from '../../../util/host-rules';
 import * as queue from '../../../util/http/queue';
@@ -69,7 +70,7 @@ export async function detectRepoFileConfig(): Promise<RepoFileConfig> {
       configFileRaw = null;
     }
     if (configFileRaw) {
-      let configFileParsed = JSON5.parse(configFileRaw);
+      let configFileParsed = parseJson(configFileRaw, configFileName) as any;
       if (configFileName !== 'package.json') {
         return { configFileName, configFileRaw, configFileParsed };
       }
@@ -177,7 +178,7 @@ export async function detectRepoFileConfig(): Promise<RepoFileConfig> {
         };
       }
       try {
-        configFileParsed = JSON5.parse(configFileRaw);
+        configFileParsed = parseJson(configFileRaw, configFileName);
       } catch (err) /* istanbul ignore next */ {
         logger.debug(
           { renovateConfig: configFileRaw },