diff --git a/lib/platform/azure/index.spec.ts b/lib/platform/azure/index.spec.ts
index 564591c734e5f343c72fb97bdbb289b0feccb4e2..38e0c7e3db9590db0bc22952ed413fdb69d92e7a 100644
--- a/lib/platform/azure/index.spec.ts
+++ b/lib/platform/azure/index.spec.ts
@@ -1196,6 +1196,18 @@ describe('platform/azure', () => {
       const res = await azure.getJsonFile('file.json');
       expect(res).toEqual(data);
     });
+    it('returns null for malformed JSON', async () => {
+      azureApi.gitApi.mockImplementationOnce(
+        () =>
+          ({
+            getItemContent: jest.fn(() =>
+              Promise.resolve(Readable.from('!@#'))
+            ),
+          } as any)
+      );
+      const res = await azure.getJsonFile('file.json');
+      expect(res).toBeNull();
+    });
     it('returns null on errors', async () => {
       azureApi.gitApi.mockImplementationOnce(
         () =>
diff --git a/lib/platform/azure/index.ts b/lib/platform/azure/index.ts
index 371592d353a7c3fd3d915bb82d89ef41ee7e2d3b..d22d788aa36ce6097b80440c160f7cb026417cc8 100644
--- a/lib/platform/azure/index.ts
+++ b/lib/platform/azure/index.ts
@@ -104,15 +104,27 @@ export async function getRepos(): Promise<string[]> {
   return repos.map((repo) => `${repo.project.name}/${repo.name}`);
 }
 
-export async function getJsonFile(
+export async function getRawFile(
   fileName: string,
   repo: string = config.repoId
-): Promise<any | null> {
+): Promise<string | null> {
   try {
     const azureApiGit = await azureApi.gitApi();
     const buf = await azureApiGit.getItemContent(repo, fileName);
     const str = await streamToString(buf);
-    return JSON.parse(str);
+    return str;
+  } catch (err) {
+    return null;
+  }
+}
+
+export async function getJsonFile(
+  fileName: string,
+  repo: string = config.repoId
+): Promise<any | null> {
+  try {
+    const raw = await getRawFile(fileName, repo);
+    return raw && JSON.parse(raw);
   } catch (err) {
     return null;
   }
diff --git a/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap b/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
index 95196af6884dcfe87d4fb026a30f56c10006de6c..25a868a27f971f32487a84f71d1948d5b1656736 100644
--- a/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/bitbucket-server/__snapshots__/index.spec.ts.snap
@@ -1972,6 +1972,47 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server/index endpoint with no path getJsonFile() returns null for malformed JSON 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/rest/api/1.0/projects/SOME/repos/repo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/rest/api/1.0/projects/SOME/repos/repo/browse/file.json?limit=20000",
+  },
+]
+`;
+
 exports[`platform/bitbucket-server/index endpoint with no path getJsonFile() returns null on errors 1`] = `
 Array [
   Object {
@@ -2310,22 +2351,6 @@ Array [
 
 exports[`platform/bitbucket-server/index endpoint with no path getPr() returns null for no prNo 1`] = `Array []`;
 
-exports[`platform/bitbucket-server/index endpoint with no path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
-
-exports[`platform/bitbucket-server/index endpoint with no path massageMarkdown() sanitizes HTML comments in the body 1`] = `
-"---
-
-- [ ] If you want to rebase/retry this PR, check this box
-- [ ] <a href=\\"/some/link\\">Update renovate/renovate to 16.1.2</a>
-
----
-
-Empty comment.
-
-Followed by some information.
-"
-`;
-
 exports[`platform/bitbucket-server/index endpoint with no path getPrList() has pr 1`] = `
 Array [
   Object {
@@ -2579,6 +2604,22 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server/index endpoint with no path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
+
+exports[`platform/bitbucket-server/index endpoint with no path massageMarkdown() sanitizes HTML comments in the body 1`] = `
+"---
+
+- [ ] If you want to rebase/retry this PR, check this box
+- [ ] <a href=\\"/some/link\\">Update renovate/renovate to 16.1.2</a>
+
+---
+
+Empty comment.
+
+Followed by some information.
+"
+`;
+
 exports[`platform/bitbucket-server/index endpoint with no path mergePr() posts Merge 1`] = `
 Array [
   Object {
@@ -6062,6 +6103,47 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server/index endpoint with path getJsonFile() returns null for malformed JSON 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/vcs/rest/api/1.0/projects/SOME/repos/repo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/vcs/rest/api/1.0/projects/SOME/repos/repo/branches/default",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "stash.renovatebot.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+      "x-atlassian-token": "no-check",
+    },
+    "method": "GET",
+    "url": "https://stash.renovatebot.com/vcs/rest/api/1.0/projects/SOME/repos/repo/browse/file.json?limit=20000",
+  },
+]
+`;
+
 exports[`platform/bitbucket-server/index endpoint with path getJsonFile() returns null on errors 1`] = `
 Array [
   Object {
@@ -6400,22 +6482,6 @@ Array [
 
 exports[`platform/bitbucket-server/index endpoint with path getPr() returns null for no prNo 1`] = `Array []`;
 
-exports[`platform/bitbucket-server/index endpoint with path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
-
-exports[`platform/bitbucket-server/index endpoint with path massageMarkdown() sanitizes HTML comments in the body 1`] = `
-"---
-
-- [ ] If you want to rebase/retry this PR, check this box
-- [ ] <a href=\\"/some/link\\">Update renovate/renovate to 16.1.2</a>
-
----
-
-Empty comment.
-
-Followed by some information.
-"
-`;
-
 exports[`platform/bitbucket-server/index endpoint with path getPrList() has pr 1`] = `
 Array [
   Object {
@@ -6669,6 +6735,22 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server/index endpoint with path massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;
+
+exports[`platform/bitbucket-server/index endpoint with path massageMarkdown() sanitizes HTML comments in the body 1`] = `
+"---
+
+- [ ] If you want to rebase/retry this PR, check this box
+- [ ] <a href=\\"/some/link\\">Update renovate/renovate to 16.1.2</a>
+
+---
+
+Empty comment.
+
+Followed by some information.
+"
+`;
+
 exports[`platform/bitbucket-server/index endpoint with path mergePr() posts Merge 1`] = `
 Array [
   Object {
diff --git a/lib/platform/bitbucket-server/index.spec.ts b/lib/platform/bitbucket-server/index.spec.ts
index 3270814462b3c97134416c6595988bc7fa237609..6e06889f121917906ffae8a0ba01e805837ce96b 100644
--- a/lib/platform/bitbucket-server/index.spec.ts
+++ b/lib/platform/bitbucket-server/index.spec.ts
@@ -2107,6 +2107,20 @@ Followed by some information.
           expect(res).toEqual(data);
           expect(httpMock.getTrace()).toMatchSnapshot();
         });
+        it('returns null for malformed JSON', async () => {
+          const scope = await initRepo();
+          scope
+            .get(
+              `${urlPath}/rest/api/1.0/projects/SOME/repos/repo/browse/file.json?limit=20000`
+            )
+            .reply(200, {
+              isLastPage: true,
+              lines: [{ text: '!@#' }],
+            });
+          const res = await bitbucket.getJsonFile('file.json');
+          expect(res).toBeNull();
+          expect(httpMock.getTrace()).toMatchSnapshot();
+        });
         it('returns null for long content', async () => {
           const scope = await initRepo();
           scope
diff --git a/lib/platform/bitbucket-server/index.ts b/lib/platform/bitbucket-server/index.ts
index 0e22456e3cc14d7946aac3b059f6ba0c2692eb0d..aba7cd62846093a9e71c868a76f65a38fd6795f1 100644
--- a/lib/platform/bitbucket-server/index.ts
+++ b/lib/platform/bitbucket-server/index.ts
@@ -118,17 +118,17 @@ export async function getRepos(): Promise<string[]> {
   }
 }
 
-export async function getJsonFile(
+export async function getRawFile(
   fileName: string,
   repo: string = config.repository
-): Promise<any | null> {
+): Promise<string | null> {
   try {
     const [project, slug] = repo.split('/');
     const fileUrl = `./rest/api/1.0/projects/${project}/repos/${slug}/browse/${fileName}?limit=20000`;
     const res = await bitbucketServerHttp.getJson<FileData>(fileUrl);
     const { isLastPage, lines, size } = res.body;
     if (isLastPage) {
-      return JSON.parse(lines.map(({ text }) => text).join(''));
+      return lines.map(({ text }) => text).join('');
     }
     logger.warn({ size }, `The file is too big`);
   } catch (err) {
@@ -137,6 +137,18 @@ export async function getJsonFile(
   return null;
 }
 
+export async function getJsonFile(
+  fileName: string,
+  repo: string = config.repository
+): Promise<any | null> {
+  try {
+    const raw = await getRawFile(fileName, repo);
+    return raw && JSON.parse(raw);
+  } catch (err) {
+    return null;
+  }
+}
+
 // Initialize BitBucket Server by getting base branch
 export async function initRepo({
   repository,
diff --git a/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap b/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap
index 8d8219f924c3c25c431361730820ff98bc9d7f74..e368a8d464fc61d44c83f6bb6c4248b6d17bd635 100644
--- a/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/bitbucket/__snapshots__/index.spec.ts.snap
@@ -908,6 +908,21 @@ Array [
     "method": "GET",
     "url": "https://api.bitbucket.org/2.0/repositories/some/repo",
   },
+  Object {
+    "headers": Object {
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "api.bitbucket.org",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://api.bitbucket.org/2.0/repositories/some/repo/src/HEAD/file.json",
+  },
+]
+`;
+
+exports[`platform/bitbucket getJsonFile() returns null for malformed JSON 1`] = `
+Array [
   Object {
     "headers": Object {
       "accept": "application/json",
@@ -917,6 +932,16 @@ Array [
       "user-agent": "https://github.com/renovatebot/renovate",
     },
     "method": "GET",
+    "url": "https://api.bitbucket.org/2.0/repositories/some/repo",
+  },
+  Object {
+    "headers": Object {
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Basic YWJjOjEyMw==",
+      "host": "api.bitbucket.org",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
     "url": "https://api.bitbucket.org/2.0/repositories/some/repo/src/HEAD/file.json",
   },
 ]
@@ -937,7 +962,6 @@ Array [
   },
   Object {
     "headers": Object {
-      "accept": "application/json",
       "accept-encoding": "gzip, deflate",
       "authorization": "Basic YWJjOjEyMw==",
       "host": "api.bitbucket.org",
diff --git a/lib/platform/bitbucket/index.spec.ts b/lib/platform/bitbucket/index.spec.ts
index 6acc6cc6d61fda32342ac1f008c7bfac0fc1f5b5..ab296ce6c03a87f9d9db039937f3a3e8a82ded00 100644
--- a/lib/platform/bitbucket/index.spec.ts
+++ b/lib/platform/bitbucket/index.spec.ts
@@ -851,6 +851,15 @@ describe('platform/bitbucket', () => {
       expect(res).toEqual(data);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+    it('returns null for malformed JSON', async () => {
+      const scope = await initRepoMock();
+      scope
+        .get('/2.0/repositories/some/repo/src/HEAD/file.json')
+        .reply(200, '!@#');
+      const res = await bitbucket.getJsonFile('file.json');
+      expect(res).toBeNull();
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
     it('returns null on errors', async () => {
       const scope = await initRepoMock();
       scope
diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts
index f6518d5a2f58912d64ba72087d8846c732647e1a..709852540c7233ef97956ec8806b24a8eefc06ba 100644
--- a/lib/platform/bitbucket/index.ts
+++ b/lib/platform/bitbucket/index.ts
@@ -99,21 +99,33 @@ export async function getRepos(): Promise<string[]> {
   }
 }
 
-export async function getJsonFile(
+export async function getRawFile(
   fileName: string,
   repo: string = config.repository
-): Promise<any | null> {
+): Promise<string | null> {
   try {
     // See: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Bworkspace%7D/%7Brepo_slug%7D/src/%7Bcommit%7D/%7Bpath%7D
     const path = fileName;
     const url = `/2.0/repositories/${repo}/src/HEAD/${path}`;
-    const res = await bitbucketHttp.getJson(url);
+    const res = await bitbucketHttp.get(url);
     return res.body;
   } catch (err) {
     return null;
   }
 }
 
+export async function getJsonFile(
+  fileName: string,
+  repo: string = config.repository
+): Promise<any | null> {
+  try {
+    const raw = await getRawFile(fileName, repo);
+    return raw && JSON.parse(raw);
+  } catch (err) {
+    return null;
+  }
+}
+
 // Initialize bitbucket by getting base branch and SHA
 export async function initRepo({
   repository,
diff --git a/lib/platform/gitea/index.spec.ts b/lib/platform/gitea/index.spec.ts
index 6559c175e8b201584739f55b6d9b2841d2033aa0..e64331ca4716bfd00a05f14b8009089802e0fb7f 100644
--- a/lib/platform/gitea/index.spec.ts
+++ b/lib/platform/gitea/index.spec.ts
@@ -1363,6 +1363,14 @@ describe(getName(__filename), () => {
       const res = await gitea.getJsonFile('file.json');
       expect(res).toEqual(data);
     });
+    it('returns null for malformed JSON', async () => {
+      helper.getRepoContents.mockResolvedValueOnce({
+        contentString: '!@#',
+      } as never);
+      await initFakeRepo({ full_name: 'some/repo' });
+      const res = await gitea.getJsonFile('file.json');
+      expect(res).toBeNull();
+    });
     it('returns null on errors', async () => {
       helper.getRepoContents.mockRejectedValueOnce('some error');
       await initFakeRepo({ full_name: 'some/repo' });
diff --git a/lib/platform/gitea/index.ts b/lib/platform/gitea/index.ts
index a6c0653972e984c17dd1aabd753daa5353e3ca26..558ff4c48b394e525c0d3e53e7f1069d5fb028ea 100644
--- a/lib/platform/gitea/index.ts
+++ b/lib/platform/gitea/index.ts
@@ -208,13 +208,25 @@ const platform: Platform = {
     };
   },
 
+  async getRawFile(
+    fileName: string,
+    repo: string = config.repository
+  ): Promise<string | null> {
+    try {
+      const contents = await helper.getRepoContents(repo, fileName);
+      return contents.contentString;
+    } catch (err) /* istanbul ignore next */ {
+      return null;
+    }
+  },
+
   async getJsonFile(
     fileName: string,
     repo: string = config.repository
   ): Promise<any | null> {
     try {
-      const contents = await helper.getRepoContents(repo, fileName);
-      return JSON.parse(contents.contentString);
+      const raw = await platform.getRawFile(fileName, repo);
+      return raw && JSON.parse(raw);
     } catch (err) /* istanbul ignore next */ {
       return null;
     }
@@ -835,6 +847,7 @@ export const {
   getBranchPr,
   getBranchStatus,
   getBranchStatusCheck,
+  getRawFile,
   getJsonFile,
   getIssueList,
   getPr,
diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap
index 222091c07e42f477e058b7e05cfb2569158fb58f..3ef809243a2736b512083d4e2ced38bbc6c4b9c0 100644
--- a/lib/platform/github/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/github/__snapshots__/index.spec.ts.snap
@@ -3454,6 +3454,57 @@ Array [
 ]
 `;
 
+exports[`platform/github getJsonFile() returns null for malformed JSON 1`] = `
+Array [
+  Object {
+    "graphql": Object {
+      "query": Object {
+        "repository": Object {
+          "__args": Object {
+            "name": "repo",
+            "owner": "some",
+          },
+          "defaultBranchRef": Object {
+            "name": null,
+            "target": Object {
+              "oid": null,
+            },
+          },
+          "isArchived": null,
+          "isFork": null,
+          "mergeCommitAllowed": null,
+          "nameWithOwner": null,
+          "rebaseMergeAllowed": null,
+          "squashMergeAllowed": null,
+        },
+      },
+    },
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "token abc123",
+      "content-length": "330",
+      "content-type": "application/json",
+      "host": "api.github.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "POST",
+    "url": "https://api.github.com/graphql",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "token abc123",
+      "host": "api.github.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://api.github.com/repos/some/repo/contents/file.json",
+  },
+]
+`;
+
 exports[`platform/github getJsonFile() returns null on errors 1`] = `
 Array [
   Object {
diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts
index 48f118641c6248497d10fe914988ff7d9900d32c..6285f2636d0f5868a83bd8164a1cd84251b78153 100644
--- a/lib/platform/github/index.spec.ts
+++ b/lib/platform/github/index.spec.ts
@@ -2152,6 +2152,17 @@ describe('platform/github', () => {
       expect(res).toEqual(data);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+    it('returns null for malformed JSON', async () => {
+      const scope = httpMock.scope(githubApiHost);
+      initRepoMock(scope, 'some/repo');
+      await github.initRepo({ repository: 'some/repo', token: 'token' } as any);
+      scope.get('/repos/some/repo/contents/file.json').reply(200, {
+        content: Buffer.from('!@#').toString('base64'),
+      });
+      const res = await github.getJsonFile('file.json');
+      expect(res).toBeNull();
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
     it('returns null on errors', async () => {
       const scope = httpMock.scope(githubApiHost);
       initRepoMock(scope, 'some/repo');
diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts
index 909987b336b8233232f284ac5952c35ee4f9b224..bb5f4256dfb6c596f68b472ca915fa24e20c8c42 100644
--- a/lib/platform/github/index.ts
+++ b/lib/platform/github/index.ts
@@ -141,17 +141,28 @@ async function getBranchProtection(
   return res.body;
 }
 
-export async function getJsonFile(
+export async function getRawFile(
   fileName: string,
   repo: string = config.repository
-): Promise<any | null> {
+): Promise<string | null> {
   try {
     const url = `repos/${repo}/contents/${fileName}`;
     const res = await githubApi.getJson<{ content: string }>(url);
     const buf = res.body.content;
     const str = Buffer.from(buf, 'base64').toString();
-    const result = JSON.parse(str);
-    return result;
+    return str;
+  } catch (err) {
+    return null;
+  }
+}
+
+export async function getJsonFile(
+  fileName: string,
+  repo: string = config.repository
+): Promise<any | null> {
+  try {
+    const raw = await getRawFile(fileName, repo);
+    return raw && JSON.parse(raw);
   } catch (err) {
     return null;
   }
diff --git a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
index 76c21f04f5b75e03daffe5b6ef9b29ffe9e9ef3b..1fa2134260a5e77f060dbd93fe340fdc33864635 100644
--- a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
@@ -1551,6 +1551,33 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab getJsonFile() returns null for malformed JSON 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/dir%2Ffile.json?ref=HEAD",
+  },
+]
+`;
+
 exports[`platform/gitlab getJsonFile() returns null on errors 1`] = `
 Array [
   Object {
diff --git a/lib/platform/gitlab/index.spec.ts b/lib/platform/gitlab/index.spec.ts
index 74cc34700d10a6a87c0f82d0d933d9f707557409..3979c7a5fef324a5a3984faf226629d1126258b6 100644
--- a/lib/platform/gitlab/index.spec.ts
+++ b/lib/platform/gitlab/index.spec.ts
@@ -1447,6 +1447,19 @@ These updates have all been created already. Click a checkbox below to force a r
       expect(res).toEqual(data);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+    it('returns null for malformed JSON', async () => {
+      const scope = await initRepo();
+      scope
+        .get(
+          '/api/v4/projects/some%2Frepo/repository/files/dir%2Ffile.json?ref=HEAD'
+        )
+        .reply(200, {
+          content: Buffer.from('!@#').toString('base64'),
+        });
+      const res = await gitlab.getJsonFile('dir/file.json');
+      expect(res).toBeNull();
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
     it('returns null on errors', async () => {
       const scope = await initRepo();
       scope
diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts
index e85be97fd9351b2c86c2b683081d9972cbac2295..06277d9f65de25cc493b35e22fa1de41dd90fddb 100755
--- a/lib/platform/gitlab/index.ts
+++ b/lib/platform/gitlab/index.ts
@@ -139,18 +139,29 @@ function urlEscape(str: string): string {
   return str ? str.replace(/\//g, '%2F') : str;
 }
 
-export async function getJsonFile(
+export async function getRawFile(
   fileName: string,
   repo: string = config.repository
-): Promise<any | null> {
+): Promise<string | null> {
   try {
     const escapedFileName = urlEscape(fileName);
     const url = `projects/${repo}/repository/files/${escapedFileName}?ref=HEAD`;
     const res = await gitlabApi.getJson<{ content: string }>(url);
     const buf = res.body.content;
     const str = Buffer.from(buf, 'base64').toString();
-    const result = JSON.parse(str);
-    return result;
+    return str;
+  } catch (err) {
+    return null;
+  }
+}
+
+export async function getJsonFile(
+  fileName: string,
+  repo: string = config.repository
+): Promise<any | null> {
+  try {
+    const raw = await getRawFile(fileName, repo);
+    return raw && JSON.parse(raw);
   } catch (err) {
     return null;
   }
diff --git a/lib/platform/types.ts b/lib/platform/types.ts
index c72e89da171e634528efc4b961c47e2b2f276d20..89345dc4518d357928432cb25ca49b80bc7a48aa 100644
--- a/lib/platform/types.ts
+++ b/lib/platform/types.ts
@@ -140,7 +140,8 @@ export interface Platform {
   findIssue(title: string): Promise<Issue | null>;
   getIssueList(): Promise<Issue[]>;
   getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]>;
-  getJsonFile(fileName: string): Promise<any | null>;
+  getRawFile(fileName: string, repo?: string): Promise<string | null>;
+  getJsonFile(fileName: string, repo?: string): Promise<any | null>;
   initRepo(config: RepoParams): Promise<RepoResult>;
   getPrList(): Promise<Pr[]>;
   ensureIssueClosing(title: string): Promise<void>;