diff --git a/lib/config/presets/github/index.ts b/lib/config/presets/github/index.ts
index 7363c3810dce02efea758a23140b9058f94f3c53..2a781f073aea6e91f4666c0b6c49c6c392b54191 100644
--- a/lib/config/presets/github/index.ts
+++ b/lib/config/presets/github/index.ts
@@ -1,6 +1,6 @@
-import { PLATFORM_FAILURE } from '../../../constants/error-messages';
 import { PLATFORM_TYPE_GITHUB } from '../../../constants/platforms';
 import { logger } from '../../../logger';
+import { ExternalHostError } from '../../../types/error';
 import { Http, HttpOptions } from '../../../util/http';
 import { Preset, PresetConfig } from '../common';
 import { PRESET_DEP_NOT_FOUND, fetchPreset } from '../util';
@@ -27,7 +27,7 @@ export async function fetchJSONFile(
     res = await http.getJson(url, opts);
   } catch (err) {
     // istanbul ignore if: not testable with nock
-    if (err.message === PLATFORM_FAILURE) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     logger.debug(
diff --git a/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap b/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap
index a04e3707f89e470426ec4b325d6d9d42e9e77098..b79273bd3835131b34c09da378f27a7a8bfee149 100644
--- a/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap
@@ -70,7 +70,7 @@ Array [
 ]
 `;
 
-exports[`config/presets/gitlab/index getPreset() throws platform-failure 1`] = `
+exports[`config/presets/gitlab/index getPreset() throws EXTERNAL_HOST_ERROR 1`] = `
 Array [
   Object {
     "headers": Object {
diff --git a/lib/config/presets/gitlab/index.spec.ts b/lib/config/presets/gitlab/index.spec.ts
index e180961dd3fb929c20a0388b4ed2e11d8f6f6d00..2d48a835a59c22e161a272852b3ae414268b8e71 100644
--- a/lib/config/presets/gitlab/index.spec.ts
+++ b/lib/config/presets/gitlab/index.spec.ts
@@ -1,6 +1,6 @@
 import * as httpMock from '../../../../test/httpMock';
 import { getName } from '../../../../test/util';
-import { PLATFORM_FAILURE } from '../../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages';
 import { PRESET_DEP_NOT_FOUND } from '../util';
 import * as gitlab from '.';
 
@@ -18,14 +18,14 @@ describe(getName(__filename), () => {
   });
 
   describe('getPreset()', () => {
-    it('throws platform-failure', async () => {
+    it('throws EXTERNAL_HOST_ERROR', async () => {
       httpMock.scope(gitlabApiHost).get(`${basePath}/branches`).reply(500);
       await expect(
         gitlab.getPreset({
           packageName: 'some/repo',
           presetName: 'non-default',
         })
-      ).rejects.toThrow(PLATFORM_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
 
diff --git a/lib/config/presets/gitlab/index.ts b/lib/config/presets/gitlab/index.ts
index 7bec62cc2fff738bcc1a99c24c7c3f85701b2ff8..a5f7eb78211cf19670193ed48058f105978334de 100644
--- a/lib/config/presets/gitlab/index.ts
+++ b/lib/config/presets/gitlab/index.ts
@@ -1,5 +1,5 @@
-import { PLATFORM_FAILURE } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
+import { ExternalHostError } from '../../../types/error';
 import type { GitLabBranch } from '../../../types/platform/gitlab';
 import { GitlabHttp } from '../../../util/http/gitlab';
 import { Preset, PresetConfig } from '../common';
@@ -42,7 +42,7 @@ export async function fetchJSONFile(
     const url = `${endpoint}projects/${urlEncodedRepo}/repository/files/${urlEncodedPkgName}/raw?ref=${defautlBranchName}`;
     return (await gitlabApi.getJson<Preset>(url)).body;
   } catch (err) {
-    if (err.message === PLATFORM_FAILURE) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     logger.debug(
diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts
index 144d068c9583442620e346c4eff5ca58ae0a9c82..3a9eea8fdfe6d134d88de3d1c22e7020a11cba63 100644
--- a/lib/config/presets/index.ts
+++ b/lib/config/presets/index.ts
@@ -1,10 +1,7 @@
 import is from '@sindresorhus/is';
-import {
-  CONFIG_VALIDATION,
-  DATASOURCE_FAILURE,
-  PLATFORM_FAILURE,
-} from '../../constants/error-messages';
+import { CONFIG_VALIDATION } from '../../constants/error-messages';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { regEx } from '../../util/regex';
 import { RenovateConfig } from '../common';
 import * as massage from '../massage';
@@ -207,10 +204,7 @@ export async function resolveConfigPresets(
         } catch (err) {
           logger.debug({ preset, err }, 'Preset fetch error');
           // istanbul ignore if
-          if (
-            err.message === PLATFORM_FAILURE ||
-            err.message === DATASOURCE_FAILURE
-          ) {
+          if (err instanceof ExternalHostError) {
             throw err;
           }
           const error = new Error(CONFIG_VALIDATION);
diff --git a/lib/constants/error-messages.ts b/lib/constants/error-messages.ts
index b1bb53ef6de252c5f0f3f4c984fdbba2d24f9b74..12ad1164c19456d807a306b5014a3046be25482c 100644
--- a/lib/constants/error-messages.ts
+++ b/lib/constants/error-messages.ts
@@ -5,7 +5,6 @@ export const SYSTEM_INSUFFICIENT_MEMORY = 'out-of-memory';
 // Platform Error
 export const PLATFORM_AUTHENTICATION_ERROR = 'authentication-error';
 export const PLATFORM_BAD_CREDENTIALS = 'bad-credentials';
-export const PLATFORM_FAILURE = 'platform-failure';
 export const PLATFORM_GPG_FAILED = 'gpg-failed';
 export const PLATFORM_INTEGRATION_UNAUTHORIZED = 'integration-unauthorized';
 export const PLATFORM_NOT_FOUND = 'platform-not-found';
@@ -34,8 +33,8 @@ export const REPOSITORY_UNINITIATED = 'uninitiated';
 export const MANAGER_LOCKFILE_ERROR = 'lockfile-error';
 export const MANAGER_NO_PACKAGE_FILES = 'no-package-files';
 
-// Datasource error
-export const DATASOURCE_FAILURE = 'registry-failure';
+// Host error
+export const EXTERNAL_HOST_ERROR = 'external-host-error';
 
 // Worker Error
 export const WORKER_FILE_UPDATE_FAILED = 'update-failure';
diff --git a/lib/datasource/cdnjs/index.spec.ts b/lib/datasource/cdnjs/index.spec.ts
index 976b61003caad9dfe131d27dd8d2be6b6267af8e..2ff92f7cbf5e6dc917e3342d6c480403879b78c8 100644
--- a/lib/datasource/cdnjs/index.spec.ts
+++ b/lib/datasource/cdnjs/index.spec.ts
@@ -1,7 +1,7 @@
 import fs from 'fs';
 import { getPkgReleases } from '..';
 import * as httpMock from '../../../test/httpMock';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import { id as datasource } from '.';
 
 let res1 = fs.readFileSync(
@@ -36,14 +36,14 @@ describe('datasource/cdnjs', () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(200, null);
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('throws for error', async () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).replyWithError('error');
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('returns null for 404', async () => {
@@ -70,28 +70,28 @@ describe('datasource/cdnjs', () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(401);
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('throws for 429', async () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(429);
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('throws for 5xx', async () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(502);
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('returns null for unknown error', async () => {
       httpMock.scope(baseUrl).get(pathFor('foo/bar')).replyWithError('error');
       await expect(
         getPkgReleases({ datasource, depName: 'foo/bar' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('processes real data', async () => {
diff --git a/lib/datasource/cdnjs/index.ts b/lib/datasource/cdnjs/index.ts
index 5b5f7f20264a72da02b50373a63617b489b0f42d..c408bd0d147e71a9296025852283da7d917e2965 100644
--- a/lib/datasource/cdnjs/index.ts
+++ b/lib/datasource/cdnjs/index.ts
@@ -1,7 +1,8 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http } from '../../util/http';
 import { CachePromise, cacheAble } from '../cache';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'cdnjs';
 
@@ -60,7 +61,7 @@ export async function getReleases({
       logger.debug({ library }, 'cdnjs library not found');
       return null;
     }
-    // Throw a DatasourceError for all other types of errors
-    throw new DatasourceError(err);
+    // Throw an ExternalHostError for all other types of errors
+    throw new ExternalHostError(err);
   }
 }
diff --git a/lib/datasource/common.ts b/lib/datasource/common.ts
index 1d4be8b8c4d349870026a12038137c1b1a770747..0f31ca9cb227eeabd92e4cc6b0176eaa33c60e2a 100644
--- a/lib/datasource/common.ts
+++ b/lib/datasource/common.ts
@@ -1,5 +1,3 @@
-import { DATASOURCE_FAILURE } from '../constants/error-messages';
-
 export interface Config {
   datasource?: string;
   depName?: string;
@@ -80,18 +78,3 @@ export interface Datasource {
   defaultConfig?: object;
   registryStrategy?: 'first' | 'hunt' | 'merge';
 }
-
-export class DatasourceError extends Error {
-  err: Error;
-
-  datasource?: string;
-
-  lookupName?: string;
-
-  constructor(err: Error) {
-    super(DATASOURCE_FAILURE);
-    // Set the prototype explicitly: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
-    Object.setPrototypeOf(this, DatasourceError.prototype);
-    this.err = err;
-  }
-}
diff --git a/lib/datasource/crate/__snapshots__/index.spec.ts.snap b/lib/datasource/crate/__snapshots__/index.spec.ts.snap
index 63116b90b9060158cf341813e3673154dfc00f09..f5d2a6e7250c73bc10de334dd593091c2aa8a933 100644
--- a/lib/datasource/crate/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/crate/__snapshots__/index.spec.ts.snap
@@ -764,7 +764,7 @@ Array [
 ]
 `;
 
-exports[`datasource/crate getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
+exports[`datasource/crate getReleases throws for 5xx 1`] = `[Error: external-host-error]`;
 
 exports[`datasource/crate getReleases throws for 5xx 2`] = `
 Array [
diff --git a/lib/datasource/crate/index.ts b/lib/datasource/crate/index.ts
index fe948c1ab79079d860859af6a4b8ecb1f98bc3a9..40134c936da8cad0065bfcba38de94b1eed7155c 100644
--- a/lib/datasource/crate/index.ts
+++ b/lib/datasource/crate/index.ts
@@ -1,12 +1,8 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
-import {
-  DatasourceError,
-  GetReleasesConfig,
-  Release,
-  ReleaseResult,
-} from '../common';
+import { GetReleasesConfig, Release, ReleaseResult } from '../common';
 
 export const id = 'crate';
 
@@ -105,7 +101,7 @@ export async function getReleases({
       err.statusCode === 429 ||
       (err.statusCode >= 500 && err.statusCode < 600)
     ) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     logger.warn({ err, lookupName }, 'crates.io lookup failure: Unknown error');
     return null;
diff --git a/lib/datasource/dart/__snapshots__/index.spec.ts.snap b/lib/datasource/dart/__snapshots__/index.spec.ts.snap
index 39f878f58fd9a7067544a245c15a5eeb743a0187..856d329c5d3f781461650006ee07f829b0e95e05 100644
--- a/lib/datasource/dart/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/dart/__snapshots__/index.spec.ts.snap
@@ -144,7 +144,7 @@ Array [
 ]
 `;
 
-exports[`datasource/dart getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
+exports[`datasource/dart getReleases throws for 5xx 1`] = `[Error: external-host-error]`;
 
 exports[`datasource/dart getReleases throws for 5xx 2`] = `
 Array [
diff --git a/lib/datasource/dart/index.ts b/lib/datasource/dart/index.ts
index e080ef053f3b51affe61e6576fb57c34e937dfd4..4043f1df5b3248cf540bf70420ee39c1ede109c7 100644
--- a/lib/datasource/dart/index.ts
+++ b/lib/datasource/dart/index.ts
@@ -1,6 +1,7 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http, HttpResponse } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'dart';
 
@@ -33,7 +34,7 @@ export async function getReleases({
       err.statusCode === 429 ||
       (err.statusCode >= 500 && err.statusCode < 600)
     ) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     logger.warn(
       { err, lookupName },
diff --git a/lib/datasource/docker/index.spec.ts b/lib/datasource/docker/index.spec.ts
index 7d2c09c7ffe7d4ec4f0be826d740bec3469162f5..2f69ffa7d3256421665d738794865a34011d3424 100644
--- a/lib/datasource/docker/index.spec.ts
+++ b/lib/datasource/docker/index.spec.ts
@@ -2,7 +2,7 @@ import AWS from 'aws-sdk';
 import AWSMock from 'aws-sdk-mock';
 import { getDigest, getPkgReleases } from '..';
 import * as httpMock from '../../../test/httpMock';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import * as _hostRules from '../../util/host-rules';
 import * as docker from '.';
 
@@ -331,13 +331,13 @@ describe('api/docker', () => {
       httpMock.scope(baseUrl).get('/').replyWithError({ statusCode: 429 });
       await expect(
         getDigest({ datasource: 'docker', depName: 'some-dep' }, 'latest')
-      ).rejects.toThrow(Error(DATASOURCE_FAILURE));
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
     });
     it('should throw error for 5xx', async () => {
       httpMock.scope(baseUrl).get('/').replyWithError({ statusCode: 504 });
       await expect(
         getDigest({ datasource: 'docker', depName: 'some-dep' }, 'latest')
-      ).rejects.toThrow(Error(DATASOURCE_FAILURE));
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
     });
   });
   describe('getReleases', () => {
diff --git a/lib/datasource/docker/index.ts b/lib/datasource/docker/index.ts
index 34536479d3370fe49f22d18f82a203cf2b47269e..7a9e57c4199f41cb1fe969d841946aa8040ef88b 100644
--- a/lib/datasource/docker/index.ts
+++ b/lib/datasource/docker/index.ts
@@ -6,10 +6,11 @@ import parseLinkHeader from 'parse-link-header';
 import wwwAuthenticate from 'www-authenticate';
 import { logger } from '../../logger';
 import { HostRule } from '../../types';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import * as hostRules from '../../util/host-rules';
 import { Http, HttpResponse } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 // TODO: add got typings when available
 // TODO: replace www-authenticate with https://www.npmjs.com/package/auth-header ?
@@ -220,14 +221,14 @@ async function getAuthHeaders(
     }
     // prettier-ignore
     if (err.name === 'RequestError' && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     // prettier-ignore
     if (err.statusCode === 429 && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     if (err.statusCode >= 500 && err.statusCode < 600) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     logger.warn(
       { registry, dockerRepository: repository, err },
@@ -267,7 +268,7 @@ async function getManifestResponse(
     });
     return manifestResponse;
   } catch (err) /* istanbul ignore next */ {
-    if (err instanceof DatasourceError) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     if (err.statusCode === 401) {
@@ -292,10 +293,10 @@ async function getManifestResponse(
     }
     // prettier-ignore
     if (err.statusCode === 429 && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     if (err.statusCode >= 500 && err.statusCode < 600) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     if (err.code === 'ETIMEDOUT') {
       logger.debug(
@@ -356,7 +357,7 @@ export async function getDigest(
       logger.debug({ digest }, 'Got docker digest');
     }
   } catch (err) /* istanbul ignore next */ {
-    if (err instanceof DatasourceError) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     logger.debug(
@@ -413,7 +414,7 @@ async function getTags(
     await globalCache.set(cacheNamespace, cacheKey, tags, cacheMinutes);
     return tags;
   } catch (err) /* istanbul ignore next */ {
-    if (err instanceof DatasourceError) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     logger.debug(
@@ -441,14 +442,14 @@ async function getTags(
         { registry, dockerRepository: repository, err },
         'docker registry failure: too many requests'
       );
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     if (err.statusCode >= 500 && err.statusCode < 600) {
       logger.warn(
         { registry, dockerRepository: repository, err },
         'docker registry failure: internal error'
       );
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     if (err.code === 'ETIMEDOUT') {
       logger.debug(
@@ -543,7 +544,7 @@ async function getLabels(
     await globalCache.set(cacheNamespace, cacheKey, labels, cacheMinutes);
     return labels;
   } catch (err) {
-    if (err instanceof DatasourceError) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     if (err.statusCode === 400 || err.statusCode === 401) {
diff --git a/lib/datasource/galaxy/__snapshots__/index.spec.ts.snap b/lib/datasource/galaxy/__snapshots__/index.spec.ts.snap
index 1ecdb5c221d5cd8371bdb0e2215671ee4bf560e9..3e2f68cc8b7ee2c79a00b22306b296134beb05d9 100644
--- a/lib/datasource/galaxy/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/galaxy/__snapshots__/index.spec.ts.snap
@@ -119,7 +119,7 @@ Array [
 ]
 `;
 
-exports[`datasource/galaxy getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
+exports[`datasource/galaxy getReleases throws for 5xx 1`] = `[Error: external-host-error]`;
 
 exports[`datasource/galaxy getReleases throws for 5xx 2`] = `
 Array [
diff --git a/lib/datasource/galaxy/index.ts b/lib/datasource/galaxy/index.ts
index ce6b9e89643596dc87c84c68103c819366f5ae60..a76942dfd4c43fefc57e8241e2460c739cfb604f 100644
--- a/lib/datasource/galaxy/index.ts
+++ b/lib/datasource/galaxy/index.ts
@@ -1,12 +1,8 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
-import {
-  DatasourceError,
-  GetReleasesConfig,
-  Release,
-  ReleaseResult,
-} from '../common';
+import { GetReleasesConfig, Release, ReleaseResult } from '../common';
 
 export const id = 'galaxy';
 
@@ -101,7 +97,7 @@ export async function getReleases({
       err.statusCode === 429 ||
       (err.statusCode >= 500 && err.statusCode < 600)
     ) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     return null;
   }
diff --git a/lib/datasource/gradle-version/index.ts b/lib/datasource/gradle-version/index.ts
index aab1d9d61399d5588f8172faabf2c624967c806c..624bb27b5ea89e5ff795f0ef8f003a5505de14d0 100644
--- a/lib/datasource/gradle-version/index.ts
+++ b/lib/datasource/gradle-version/index.ts
@@ -1,7 +1,8 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http } from '../../util/http';
 import { regEx } from '../../util/regex';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'gradle-version';
 export const defaultRegistryUrls = ['https://services.gradle.org/versions/all'];
@@ -50,7 +51,7 @@ export async function getReleases({
       }));
   } catch (err) /* istanbul ignore next */ {
     if (err.host === 'services.gradle.org') {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     logger.debug({ err }, 'gradle-version err');
     return null;
diff --git a/lib/datasource/helm/__snapshots__/index.spec.ts.snap b/lib/datasource/helm/__snapshots__/index.spec.ts.snap
index 8ae2aea4bbf36fbac5cd5f557f1cd0bc4738f687..d348280ab66f4624103c6120f5b56133e02a9811 100644
--- a/lib/datasource/helm/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/helm/__snapshots__/index.spec.ts.snap
@@ -244,7 +244,7 @@ Array [
 ]
 `;
 
-exports[`datasource/helm getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
+exports[`datasource/helm getReleases throws for 5xx 1`] = `[Error: external-host-error]`;
 
 exports[`datasource/helm getReleases throws for 5xx 2`] = `
 Array [
diff --git a/lib/datasource/helm/index.ts b/lib/datasource/helm/index.ts
index 4b684275219c16ee33dfaf1ebe6b29a2f25b7d54..5ba8ba238fa10e3056c9f34fe2183982c34a3204 100644
--- a/lib/datasource/helm/index.ts
+++ b/lib/datasource/helm/index.ts
@@ -1,10 +1,11 @@
 import yaml from 'js-yaml';
 
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
 import { ensureTrailingSlash } from '../../util/url';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'helm';
 
@@ -60,7 +61,7 @@ export async function getRepositoryData(
       err.statusCode === 429 ||
       (err.statusCode >= 500 && err.statusCode < 600)
     ) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     // istanbul ignore if
     if (err.name === 'UnsupportedProtocolError') {
diff --git a/lib/datasource/hex/index.spec.ts b/lib/datasource/hex/index.spec.ts
index a751a20da5061b8bb1ae28966653e5cbb10026b7..14dabf83f2dfdaaa5956d3679e9ae43ac2350e26 100644
--- a/lib/datasource/hex/index.spec.ts
+++ b/lib/datasource/hex/index.spec.ts
@@ -1,7 +1,7 @@
 import fs from 'fs';
 import { getPkgReleases } from '..';
 import * as httpMock from '../../../test/httpMock';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import * as _hostRules from '../../util/host-rules';
 import { id as datasource } from '.';
 
@@ -67,14 +67,14 @@ describe('datasource/hex', () => {
       httpMock.scope(baseUrl).get('/some_crate').reply(429);
       await expect(
         getPkgReleases({ datasource, depName: 'some_crate' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('throws for 5xx', async () => {
       httpMock.scope(baseUrl).get('/some_crate').reply(502);
       await expect(
         getPkgReleases({ datasource, depName: 'some_crate' })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('returns null for unknown error', async () => {
diff --git a/lib/datasource/hex/index.ts b/lib/datasource/hex/index.ts
index dc614c97ee1897f747c93a2ba6f0842adf0a4706..c619cbffc0ba13fb7d502dec4697b6e6789c5513 100644
--- a/lib/datasource/hex/index.ts
+++ b/lib/datasource/hex/index.ts
@@ -1,6 +1,7 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'hex';
 
@@ -69,7 +70,7 @@ export async function getReleases({
       err.statusCode === 429 ||
       (err.statusCode >= 500 && err.statusCode < 600)
     ) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
 
     if (err.statusCode === 401) {
diff --git a/lib/datasource/index.spec.ts b/lib/datasource/index.spec.ts
index 974003a4b0e4e9e56d26d561c54dddbf8281f8ab..34aa6531a7a9bc69328cda31d2c1e5b66bfc11c0 100644
--- a/lib/datasource/index.spec.ts
+++ b/lib/datasource/index.spec.ts
@@ -1,7 +1,7 @@
 import { mocked } from '../../test/util';
-import { DATASOURCE_FAILURE } from '../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../constants/error-messages';
+import { ExternalHostError } from '../types/error';
 import { loadModules } from '../util/modules';
-import { DatasourceError } from './common';
 import * as datasourceDocker from './docker';
 import * as datasourceGithubTags from './github-tags';
 import * as datasourceMaven from './maven';
@@ -131,9 +131,9 @@ describe('datasource/index', () => {
     });
     expect(res).not.toBeNull();
   });
-  it('hunts registries and aborts on DatasourceError', async () => {
+  it('hunts registries and aborts on ExternalHostError', async () => {
     packagistDatasource.getReleases.mockImplementationOnce(() => {
-      throw new DatasourceError(new Error());
+      throw new ExternalHostError(new Error());
     });
     await expect(
       datasource.getPkgReleases({
@@ -141,7 +141,7 @@ describe('datasource/index', () => {
         depName: 'something',
         registryUrls: ['https://reg1.com', 'https://reg2.io'],
       })
-    ).rejects.toThrow(DATASOURCE_FAILURE);
+    ).rejects.toThrow(EXTERNAL_HOST_ERROR);
   });
   it('hunts registries and passes on error', async () => {
     packagistDatasource.getReleases.mockImplementationOnce(() => {
@@ -173,9 +173,9 @@ describe('datasource/index', () => {
     expect(res).toMatchSnapshot();
     expect(res.releases).toHaveLength(2);
   });
-  it('merges registries and aborts on DatasourceError', async () => {
+  it('merges registries and aborts on ExternalHostError', async () => {
     mavenDatasource.getReleases.mockImplementationOnce(() => {
-      throw new DatasourceError(new Error());
+      throw new ExternalHostError(new Error());
     });
     await expect(
       datasource.getPkgReleases({
@@ -183,7 +183,7 @@ describe('datasource/index', () => {
         depName: 'something',
         registryUrls: ['https://reg1.com', 'https://reg2.io'],
       })
-    ).rejects.toThrow(DATASOURCE_FAILURE);
+    ).rejects.toThrow(EXTERNAL_HOST_ERROR);
   });
   it('merges registries and passes on error', async () => {
     mavenDatasource.getReleases.mockImplementationOnce(() => {
diff --git a/lib/datasource/index.ts b/lib/datasource/index.ts
index 68cd63b9512783e5bcbdff179aed323e60060c9d..dba7f32e5fef06c1efdb58cbfb6e45efcdfd9a4a 100644
--- a/lib/datasource/index.ts
+++ b/lib/datasource/index.ts
@@ -1,13 +1,13 @@
 import is from '@sindresorhus/is';
 import _ from 'lodash';
 import { logger } from '../logger';
+import { ExternalHostError } from '../types/error';
 import * as runCache from '../util/cache/run';
 import { clone } from '../util/clone';
 import * as allVersioning from '../versioning';
 import datasources from './api.generated';
 import {
   Datasource,
-  DatasourceError,
   DigestConfig,
   GetPkgReleasesConfig,
   GetReleasesConfig,
@@ -65,7 +65,7 @@ async function huntRegistries(
         break;
       }
     } catch (err) {
-      if (err instanceof DatasourceError) {
+      if (err instanceof ExternalHostError) {
         throw err;
       }
       // We'll always save the last-thrown error
@@ -100,7 +100,7 @@ async function mergeRegistries(
         combinedRes = res;
       }
     } catch (err) {
-      if (err instanceof DatasourceError) {
+      if (err instanceof ExternalHostError) {
         throw err;
       }
       // We'll always save the last-thrown error
@@ -221,8 +221,8 @@ export async function getPkgReleases(
       })
     );
   } catch (e) /* istanbul ignore next */ {
-    if (e instanceof DatasourceError) {
-      e.datasource = config.datasource;
+    if (e instanceof ExternalHostError) {
+      e.hostType = config.datasource;
       e.lookupName = lookupName;
     }
     throw e;
diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts
index bbe3d11b6d0709499e72a31c9a2b4487af851a68..4349d4ba29f1491ce72ddd602e0ab77643ebaed6 100644
--- a/lib/datasource/maven/index.spec.ts
+++ b/lib/datasource/maven/index.spec.ts
@@ -2,7 +2,7 @@ import fs from 'fs';
 import { resolve } from 'path';
 import nock from 'nock';
 import { getPkgReleases } from '..';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import * as hostRules from '../../util/host-rules';
 import * as mavenVersioning from '../../versioning/maven';
 import { id as datasource } from '.';
@@ -182,7 +182,7 @@ describe('datasource/maven', () => {
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
-    it('should throw registry-failure if default maven repo fails', async () => {
+    it('should throw external-host-error if default maven repo fails', async () => {
       nock('https://repo.maven.apache.org')
         .get('/maven2/org/artifact/maven-metadata.xml')
         .times(4)
@@ -195,7 +195,7 @@ describe('datasource/maven', () => {
           depName: 'org:artifact',
           registryUrls: ['https://repo.maven.apache.org/maven2/'],
         })
-      ).rejects.toThrow(Error(DATASOURCE_FAILURE));
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
     });
 
     it('should return all versions of a specific library if a repository fails because invalid protocol', async () => {
diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts
index 4639aea1c3930240d92618b74ae66cc0dd5d601a..bb03867e9a390ff1fa47f8d69c7cfe4daf192277 100644
--- a/lib/datasource/maven/util.ts
+++ b/lib/datasource/maven/util.ts
@@ -1,7 +1,7 @@
 import url from 'url';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http } from '../../util/http';
-import { DatasourceError } from '../common';
 
 import { MAVEN_REPO, id } from './common';
 
@@ -77,7 +77,7 @@ export async function downloadHttpProtocol(
     } else if (isTemporalError(err)) {
       logger.debug({ failedUrl, err }, 'Temporary error');
       if (isMavenCentral(pkgUrl)) {
-        throw new DatasourceError(err);
+        throw new ExternalHostError(err);
       }
     } else if (isConnectionError(err)) {
       // istanbul ignore next
diff --git a/lib/datasource/npm/get.spec.ts b/lib/datasource/npm/get.spec.ts
index 2d394b010d4ade2c13ebeac2b81fe5c46868fcca..ec305f257982ecc0099f1f7e14660a3a552284a4 100644
--- a/lib/datasource/npm/get.spec.ts
+++ b/lib/datasource/npm/get.spec.ts
@@ -1,6 +1,6 @@
 import * as httpMock from '../../../test/httpMock';
 import { getName } from '../../../test/util';
-import { DatasourceError } from '../common';
+import { ExternalHostError } from '../../types/error';
 import { getDependency, resetMemCache } from './get';
 import { setNpmrc } from './npmrc';
 
@@ -150,7 +150,7 @@ describe(getName(__filename), () => {
       .get('/npm-parse-error')
       .reply(200, 'not-a-json');
     await expect(getDependency('npm-parse-error', 0)).rejects.toThrow(
-      DatasourceError
+      ExternalHostError
     );
 
     httpMock
diff --git a/lib/datasource/npm/get.ts b/lib/datasource/npm/get.ts
index d2f0e2ab362cc62d063f056b94141fb74583c683..dee919732af7e72285a0d4ff6d027136c371de16 100644
--- a/lib/datasource/npm/get.ts
+++ b/lib/datasource/npm/get.ts
@@ -6,11 +6,12 @@ import moment from 'moment';
 import registryAuthToken from 'registry-auth-token';
 import getRegistryUrl from 'registry-auth-token/registry-url';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { find } from '../../util/host-rules';
 import { Http, HttpOptions } from '../../util/http';
 import { maskToken } from '../../util/mask';
-import { DatasourceError, Release, ReleaseResult } from '../common';
+import { Release, ReleaseResult } from '../common';
 import { id } from './common';
 import { getNpmrc } from './npmrc';
 
@@ -280,7 +281,7 @@ export async function getDependency(
       if (err.name === 'ParseError' && err.body) {
         err.body = 'err.body deleted by Renovate';
       }
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     return null;
   }
diff --git a/lib/datasource/npm/index.spec.ts b/lib/datasource/npm/index.spec.ts
index f2106aacbc6c1eb59c142722cbb654e62e4d0a87..00dfde3e164bcef47af58ccbea0c26e7ce7b5cc6 100644
--- a/lib/datasource/npm/index.spec.ts
+++ b/lib/datasource/npm/index.spec.ts
@@ -3,7 +3,7 @@ import nock from 'nock';
 import _registryAuthToken from 'registry-auth-token';
 import { getPkgReleases } from '..';
 import { getName } from '../../../test/util';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import * as hostRules from '../../util/host-rules';
 import { id as datasource, getNpmrc, resetCache, setNpmrc } from '.';
 
@@ -204,13 +204,13 @@ describe(getName(__filename), () => {
     nock('https://registry.npmjs.org').get('/foobar').reply(503);
     await expect(
       getPkgReleases({ datasource, depName: 'foobar' })
-    ).rejects.toThrow(Error(DATASOURCE_FAILURE));
+    ).rejects.toThrow(EXTERNAL_HOST_ERROR);
   });
   it('should throw error for 408', async () => {
     nock('https://registry.npmjs.org').get('/foobar').reply(408);
     await expect(
       getPkgReleases({ datasource, depName: 'foobar' })
-    ).rejects.toThrow(Error(DATASOURCE_FAILURE));
+    ).rejects.toThrow(EXTERNAL_HOST_ERROR);
   });
   it('should throw error for others', async () => {
     nock('https://registry.npmjs.org').get('/foobar').reply(451);
diff --git a/lib/datasource/packagist/index.ts b/lib/datasource/packagist/index.ts
index 77946c2bb4cb3d04fd162c789e76e6ebc680c39e..7fce259e40b1d5e7e3f343cc6f33bfb913b1b6b5 100644
--- a/lib/datasource/packagist/index.ts
+++ b/lib/datasource/packagist/index.ts
@@ -2,11 +2,12 @@ import URL from 'url';
 
 import pAll from 'p-all';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import * as runCache from '../../util/cache/run';
 import * as hostRules from '../../util/host-rules';
 import { Http, HttpOptions } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'packagist';
 export const defaultRegistryUrls = ['https://packagist.org'];
@@ -313,10 +314,10 @@ async function packageLookup(
     }
     if (err.host === 'packagist.org') {
       if (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT') {
-        throw new DatasourceError(err);
+        throw new ExternalHostError(err);
       }
       if (err.statusCode && err.statusCode >= 500 && err.statusCode < 600) {
-        throw new DatasourceError(err);
+        throw new ExternalHostError(err);
       }
     }
     logger.warn({ err, name }, 'packagist registry failure: Unknown error');
diff --git a/lib/datasource/pod/index.spec.ts b/lib/datasource/pod/index.spec.ts
index 7a637e56befb68d67a0d64f509b2b737213c4df1..780f51d935b4d6e70ed5e6a121c371afead91a1d 100644
--- a/lib/datasource/pod/index.spec.ts
+++ b/lib/datasource/pod/index.spec.ts
@@ -1,5 +1,6 @@
 import { getPkgReleases } from '..';
 import * as httpMock from '../../../test/httpMock';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import * as rubyVersioning from '../../versioning/ruby';
 import * as pod from '.';
 
@@ -63,7 +64,7 @@ describe('datasource/cocoapods', () => {
         .scope(cocoapodsHost)
         .get('/all_pods_versions_a_c_b.txt')
         .reply(429);
-      await expect(getPkgReleases(config)).rejects.toThrow('registry-failure');
+      await expect(getPkgReleases(config)).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('returns null for unknown error', async () => {
diff --git a/lib/datasource/pod/index.ts b/lib/datasource/pod/index.ts
index 24b0361f875175a94979be82c04b2976c4c563a5..391719f73187cb3e7d924db3428965f2bed96161 100644
--- a/lib/datasource/pod/index.ts
+++ b/lib/datasource/pod/index.ts
@@ -1,5 +1,6 @@
 import crypto from 'crypto';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
 import { GithubHttp } from '../../util/http/github';
@@ -44,7 +45,7 @@ function handleError(lookupName: string, err: Error): void {
     (err.statusCode >= 500 && err.statusCode < 600)
   ) {
     logger.warn({ lookupName, err }, `CocoaPods registry failure`);
-    throw new Error('registry-failure');
+    throw new ExternalHostError(err);
   }
 
   if (err.statusCode === 401) {
diff --git a/lib/datasource/repology/index.spec.ts b/lib/datasource/repology/index.spec.ts
index 56b34cdcab70861aa23dc2c8c6c66ea00eb63781..bd08b9d04eb2237939ac6947622c8431e977a55e 100644
--- a/lib/datasource/repology/index.spec.ts
+++ b/lib/datasource/repology/index.spec.ts
@@ -2,7 +2,7 @@ import fs from 'fs';
 import { getPkgReleases } from '..';
 import * as httpMock from '../../../test/httpMock';
 import { getName } from '../../../test/util';
-import { DATASOURCE_FAILURE } from '../../constants/error-messages';
+import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
 import { id as versioning } from '../../versioning/loose';
 import { RepologyPackage, id as datasource } from '.';
 
@@ -127,7 +127,7 @@ describe(getName(__filename), () => {
           versioning,
           depName: 'debian_stable/nginx',
         })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
 
@@ -140,7 +140,7 @@ describe(getName(__filename), () => {
           versioning,
           depName: 'debian_stable/nginx',
         })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
 
@@ -151,7 +151,7 @@ describe(getName(__filename), () => {
           versioning,
           depName: 'invalid-lookup-name',
         })
-      ).rejects.toThrow(DATASOURCE_FAILURE);
+      ).rejects.toThrow(EXTERNAL_HOST_ERROR);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
 
diff --git a/lib/datasource/repology/index.ts b/lib/datasource/repology/index.ts
index e45c10f021ed23d0954a481f22b33593b8aaa26e..7af17eb7753cff4aa5c456a19ea24c7f81a7dca4 100644
--- a/lib/datasource/repology/index.ts
+++ b/lib/datasource/repology/index.ts
@@ -1,8 +1,9 @@
 import { URLSearchParams } from 'url';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'repology';
 
@@ -117,7 +118,7 @@ export async function getReleases({
   // Ensure lookup name contains both repository and package
   const [repoName, pkgName] = lookupName.split('/', 2);
   if (!repoName || !pkgName) {
-    throw new DatasourceError(
+    throw new ExternalHostError(
       new Error(
         'Repology lookup name must contain repository and package separated by slash (<repo>/<pkg>)'
       )
@@ -142,6 +143,6 @@ export async function getReleases({
       { lookupName, err },
       'Repology lookup failed with unexpected error'
     );
-    throw new DatasourceError(err);
+    throw new ExternalHostError(err);
   }
 }
diff --git a/lib/datasource/ruby-version/index.ts b/lib/datasource/ruby-version/index.ts
index c3315f04e16dc2bc3bf061eb36483aab316da2b1..d85ee6cec9d5915ea804cea0df3dcb17387b87eb 100644
--- a/lib/datasource/ruby-version/index.ts
+++ b/lib/datasource/ruby-version/index.ts
@@ -1,9 +1,10 @@
 import { parse } from 'node-html-parser';
 
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
 import { isVersion } from '../../versioning/ruby';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'ruby-version';
 
@@ -51,6 +52,6 @@ export async function getReleases(
     await globalCache.set(cacheNamespace, 'all', res, 15);
     return res;
   } catch (err) {
-    throw new DatasourceError(err);
+    throw new ExternalHostError(err);
   }
 }
diff --git a/lib/datasource/rubygems/get-rubygems-org.ts b/lib/datasource/rubygems/get-rubygems-org.ts
index 3eb01a4ed97a8826576338723d474925fcc8156e..f3005573227fa5ca68967d4a669f33377bfbc0e8 100644
--- a/lib/datasource/rubygems/get-rubygems-org.ts
+++ b/lib/datasource/rubygems/get-rubygems-org.ts
@@ -1,6 +1,7 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http } from '../../util/http';
-import { DatasourceError, ReleaseResult } from '../common';
+import { ReleaseResult } from '../common';
 import { id } from './common';
 
 const http = new Http(id);
@@ -38,7 +39,7 @@ async function updateRubyGemsVersions(): Promise<void> {
     if (err.statusCode !== 416) {
       contentLength = 0;
       packageReleases = Object.create(null); // Because we might need a "constructor" key
-      throw new DatasourceError(
+      throw new ExternalHostError(
         new Error('Rubygems fetch error - need to reset cache')
       );
     }
diff --git a/lib/datasource/terraform-module/index.ts b/lib/datasource/terraform-module/index.ts
index da0bce26adee168bd889b4dae404c2d868a9e27a..4cac9a7d805a35f464e8128528024a873b2049b0 100644
--- a/lib/datasource/terraform-module/index.ts
+++ b/lib/datasource/terraform-module/index.ts
@@ -1,7 +1,8 @@
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as globalCache from '../../util/cache/global';
 import { Http } from '../../util/http';
-import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
+import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'terraform-module';
 export const defaultRegistryUrls = ['https://registry.terraform.io'];
@@ -113,7 +114,7 @@ export async function getReleases({
     const failureCodes = ['EAI_AGAIN'];
     // istanbul ignore if
     if (failureCodes.includes(err.code)) {
-      throw new DatasourceError(err);
+      throw new ExternalHostError(err);
     }
     logger.warn(
       { err, lookupName },
diff --git a/lib/manager/gradle/index.ts b/lib/manager/gradle/index.ts
index 0d1ea33e155350a4f8568efacbfc578581d1ce50..2b1d02d87b1946a92db2fa3064597fac93616e41 100644
--- a/lib/manager/gradle/index.ts
+++ b/lib/manager/gradle/index.ts
@@ -3,9 +3,9 @@ import * as os from 'os';
 import * as fs from 'fs-extra';
 import upath from 'upath';
 import { LANGUAGE_JAVA } from '../../constants/languages';
-import { DatasourceError } from '../../datasource';
 import * as datasourceMaven from '../../datasource/maven';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { ExecOptions, exec } from '../../util/exec';
 import { BinarySource } from '../../util/exec/common';
 import { readLocalFile } from '../../util/fs';
@@ -106,9 +106,7 @@ export async function executeGradle(
     ({ stdout, stderr } = await exec(cmd, execOptions));
   } catch (err) /* istanbul ignore next */ {
     if (err.code === TIMEOUT_CODE) {
-      const error = new DatasourceError(err);
-      error.datasource = 'gradle';
-      throw error;
+      throw new ExternalHostError(err, 'gradle');
     }
     logger.warn({ errMessage: err.message }, 'Gradle extraction failed');
     return;
diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts
index 7ba4aae6f2832bbe18e5a78a26532ce8625dd4e5..75cf85f9c3f6c768ad7803cd41efdbe605faf2c8 100644
--- a/lib/manager/npm/post-update/index.ts
+++ b/lib/manager/npm/post-update/index.ts
@@ -3,9 +3,10 @@ import fs from 'fs-extra';
 import upath from 'upath';
 // eslint-disable-next-line import/no-unresolved
 import { SYSTEM_INSUFFICIENT_DISK_SPACE } from '../../../constants/error-messages';
-import { DatasourceError } from '../../../datasource/common';
+import { id as npmId } from '../../../datasource/npm';
 import { logger } from '../../../logger';
 import { platform } from '../../../platform';
+import { ExternalHostError } from '../../../types/error';
 import { getChildProcessEnv } from '../../../util/exec/env';
 import { deleteLocalFile } from '../../../util/fs';
 import * as hostRules from '../../../util/host-rules';
@@ -432,7 +433,7 @@ export async function getAdditionalFiles(
             const err = new Error(
               'lock file failed for the dependency being updated - skipping branch creation'
             );
-            throw new DatasourceError(err);
+            throw new ExternalHostError(err, npmId);
           }
         }
       }
@@ -492,10 +493,11 @@ export async function getAdditionalFiles(
               { dependency: upgrade.depName, type: 'yarn' },
               'lock file failed for the dependency being updated - skipping branch creation'
             );
-            throw new DatasourceError(
+            throw new ExternalHostError(
               new Error(
                 'lock file failed for the dependency being updated - skipping branch creation'
-              )
+              ),
+              npmId
             );
           }
           /* eslint-enable no-useless-escape */
@@ -594,10 +596,11 @@ export async function getAdditionalFiles(
               { dependency: upgrade.depName, type: 'pnpm' },
               'lock file failed for the dependency being updated - skipping branch creation'
             );
-            throw new DatasourceError(
+            throw new ExternalHostError(
               Error(
                 'lock file failed for the dependency being updated - skipping branch creation'
-              )
+              ),
+              npmId
             );
           }
         }
@@ -672,10 +675,11 @@ export async function getAdditionalFiles(
             { dependency: upgrade.depName, type: 'yarn' },
             'lock file failed for the dependency being updated - skipping branch creation'
           );
-          throw new DatasourceError(
+          throw new ExternalHostError(
             Error(
               'lock file failed for the dependency being updated - skipping branch creation'
-            )
+            ),
+            npmId
           );
         }
         /* eslint-enable no-useless-escape */
@@ -688,10 +692,11 @@ export async function getAdditionalFiles(
             { dependency: upgrade.depName, type: 'npm' },
             'lock file failed for the dependency being updated - skipping branch creation'
           );
-          throw new DatasourceError(
+          throw new ExternalHostError(
             Error(
               'lock file failed for the dependency being updated - skipping branch creation'
-            )
+            ),
+            npmId
           );
         }
       }
diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts
index 81d2d6e8d7e32a8db2f0d549a46abb535af8bc2a..1dcc798c0b18847d1ec3c4c0c2a6a0f40dc98e69 100644
--- a/lib/manager/npm/post-update/yarn.ts
+++ b/lib/manager/npm/post-update/yarn.ts
@@ -4,8 +4,9 @@ import { validRange } from 'semver';
 import { quote } from 'shlex';
 import { join } from 'upath';
 import { SYSTEM_INSUFFICIENT_DISK_SPACE } from '../../../constants/error-messages';
-import { DatasourceError } from '../../../datasource';
+import { id as npmId } from '../../../datasource/npm';
 import { logger } from '../../../logger';
+import { ExternalHostError } from '../../../types/error';
 import { ExecOptions, exec } from '../../../util/exec';
 import { PostUpdateConfig, Upgrade } from '../../common';
 import { getNodeConstraint } from './node-version';
@@ -151,7 +152,7 @@ export async function generateLockFile(
         err.stderr.includes('getaddrinfo ENOTFOUND registry.yarnpkg.com') ||
         err.stderr.includes('getaddrinfo ENOTFOUND registry.npmjs.org')
       ) {
-        throw new DatasourceError(err);
+        throw new ExternalHostError(err, npmId);
       }
     }
     return { error: true, stderr: err.stderr };
diff --git a/lib/platform/git/storage.ts b/lib/platform/git/storage.ts
index 1784abbfc1ebc38eedebb8bba149b26910114fc4..b857ed7f36e753f692b69fb34a3bce6b20a3bd5f 100644
--- a/lib/platform/git/storage.ts
+++ b/lib/platform/git/storage.ts
@@ -4,13 +4,13 @@ import fs from 'fs-extra';
 import Git from 'simple-git/promise';
 import {
   CONFIG_VALIDATION,
-  PLATFORM_FAILURE,
   REPOSITORY_CHANGED,
   REPOSITORY_EMPTY,
   REPOSITORY_TEMPORARY_ERROR,
   SYSTEM_INSUFFICIENT_DISK_SPACE,
 } from '../../constants/error-messages';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import * as limits from '../../workers/global/limits';
 import { CommitFilesConfig } from '../common';
 import { writePrivateKey } from './private-key';
@@ -54,7 +54,7 @@ function checkForPlatformFailure(err: Error): void {
   ];
   for (const errorStr of platformFailureStrings) {
     if (err.message.includes(errorStr)) {
-      throw new Error(PLATFORM_FAILURE);
+      throw new ExternalHostError(err, 'git');
     }
   }
 }
@@ -176,7 +176,7 @@ export class Storage {
         if (err.message?.includes('write error: No space left on device')) {
           throw new Error(SYSTEM_INSUFFICIENT_DISK_SPACE);
         }
-        throw new Error(PLATFORM_FAILURE);
+        throw new ExternalHostError(err, 'git');
       }
       const durationMs = Math.round(Date.now() - cloneStart);
       logger.debug({ durationMs }, 'git clone completed');
diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts
index 62f77f00ab60f4da7cb7c18237e79ec6dd7c0c14..644643b558675ee1c8cc505ea34578b0515ad60d 100644
--- a/lib/platform/github/index.ts
+++ b/lib/platform/github/index.ts
@@ -3,7 +3,6 @@ import is from '@sindresorhus/is';
 import delay from 'delay';
 import { configFileNames } from '../../config/app-strings';
 import {
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   REPOSITORY_ACCESS_FORBIDDEN,
   REPOSITORY_ARCHIVED,
@@ -24,6 +23,7 @@ import {
 } from '../../constants/pull-requests';
 import { logger } from '../../logger';
 import { BranchStatus } from '../../types';
+import { ExternalHostError } from '../../types/error';
 import * as hostRules from '../../util/host-rules';
 import * as githubHttp from '../../util/http/github';
 import { sanitize } from '../../util/sanitize';
@@ -397,7 +397,7 @@ export async function initRepo({
           }
         );
       } catch (err) /* istanbul ignore next */ {
-        if (err.message === PLATFORM_FAILURE) {
+        if (err instanceof ExternalHostError) {
           throw err;
         }
         if (
@@ -965,7 +965,7 @@ export async function getPrList(): Promise<Pr[]> {
       );
     } catch (err) /* istanbul ignore next */ {
       logger.debug({ err }, 'getPrList err');
-      throw new Error('platform-failure');
+      throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
     }
     config.prList = res.body.map((pr) => ({
       number: pr.number,
@@ -1094,7 +1094,7 @@ export async function getBranchStatus(
         logger.debug({ result: checkRunsRaw }, 'No check runs found');
       }
     } catch (err) /* istanbul ignore next */ {
-      if (err.message === PLATFORM_FAILURE) {
+      if (err instanceof ExternalHostError) {
         throw err;
       }
       if (
@@ -1506,7 +1506,7 @@ async function getComments(issueNo: number): Promise<Comment[]> {
   } catch (err) /* istanbul ignore next */ {
     if (err.statusCode === 404) {
       logger.debug('404 respose when retrieving comments');
-      throw new Error(PLATFORM_FAILURE);
+      throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
     }
     throw err;
   }
@@ -1559,7 +1559,7 @@ export async function ensureComment({
     }
     return true;
   } catch (err) /* istanbul ignore next */ {
-    if (err.message === PLATFORM_FAILURE) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     if (err.body?.message?.includes('is locked')) {
@@ -1690,7 +1690,7 @@ export async function updatePr(
     );
     logger.debug({ pr: prNo }, 'PR updated');
   } catch (err) /* istanbul ignore next */ {
-    if (err.message === PLATFORM_FAILURE) {
+    if (err instanceof ExternalHostError) {
       throw err;
     }
     logger.warn({ err }, 'Error updating PR');
diff --git a/lib/types/error.ts b/lib/types/error.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6e67592d0b28a10f11d88f16b13371f45a059ce
--- /dev/null
+++ b/lib/types/error.ts
@@ -0,0 +1,19 @@
+import { EXTERNAL_HOST_ERROR } from '../constants/error-messages';
+
+export class ExternalHostError extends Error {
+  hostType: string;
+
+  err: Error;
+
+  lookupName?: string;
+
+  reason?: string;
+
+  constructor(err: Error, hostType?: string) {
+    super(EXTERNAL_HOST_ERROR);
+    // Set the prototype explicitly: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
+    Object.setPrototypeOf(this, ExternalHostError.prototype);
+    this.hostType = hostType;
+    this.err = err;
+  }
+}
diff --git a/lib/util/http/github.spec.ts b/lib/util/http/github.spec.ts
index 444d9ef06c0cbd2fb103f9a92ffda6a61aec7e98..fb4e5b38aa35fc78a32dfa126212d3d2bd1ed752 100644
--- a/lib/util/http/github.spec.ts
+++ b/lib/util/http/github.spec.ts
@@ -2,8 +2,8 @@ import delay from 'delay';
 import * as httpMock from '../../../test/httpMock';
 import { getName } from '../../../test/util';
 import {
+  EXTERNAL_HOST_ERROR,
   PLATFORM_BAD_CREDENTIALS,
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_CHANGED,
@@ -126,7 +126,7 @@ describe(getName(__filename), () => {
         },
       });
       expect(e).toBeDefined();
-      expect(e.message).toEqual(PLATFORM_FAILURE);
+      expect(e.message).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('should throw platform failure for ENOTFOUND, ETIMEDOUT or EAI_AGAIN', () => {
       const codes = ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'];
@@ -137,7 +137,7 @@ describe(getName(__filename), () => {
           code,
         });
         expect(e).toBeDefined();
-        expect(e.message).toEqual(PLATFORM_FAILURE);
+        expect(e.message).toEqual(EXTERNAL_HOST_ERROR);
       }
     });
     it('should throw platform failure for 500', () => {
@@ -146,14 +146,14 @@ describe(getName(__filename), () => {
         message: 'Internal Server Error',
       });
       expect(e).toBeDefined();
-      expect(e.message).toEqual(PLATFORM_FAILURE);
+      expect(e.message).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('should throw platform failure ParseError', () => {
       const e = getError({
         name: 'ParseError',
       });
       expect(e).toBeDefined();
-      expect(e.message).toEqual(PLATFORM_FAILURE);
+      expect(e.message).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('should throw for unauthorized integration', () => {
       const e = getError({
@@ -200,7 +200,7 @@ describe(getName(__filename), () => {
       };
       const e = getError(gotErr);
       expect(e).toBeDefined();
-      expect(e.message).toEqual(PLATFORM_FAILURE);
+      expect(e.message).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('should throw original error when failed to add reviewers', () => {
       const gotErr = {
diff --git a/lib/util/http/github.ts b/lib/util/http/github.ts
index 76c7d9d76db75185c5dfab59f4dedea5847a264f..c2f6dd1b657c28bb8728bacf63c8fa3b1525c097 100644
--- a/lib/util/http/github.ts
+++ b/lib/util/http/github.ts
@@ -4,13 +4,13 @@ import pAll from 'p-all';
 import parseLinkHeader from 'parse-link-header';
 import {
   PLATFORM_BAD_CREDENTIALS,
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_CHANGED,
 } from '../../constants/error-messages';
 import { PLATFORM_TYPE_GITHUB } from '../../constants/platforms';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { maskToken } from '../mask';
 import { Http, HttpPostOptions, HttpResponse, InternalHttpOptions } from '.';
 
@@ -61,15 +61,15 @@ export function handleGotError(
       err.code === 'EAI_AGAIN')
   ) {
     logger.debug({ err }, 'GitHub failure: RequestError');
-    throw new Error(PLATFORM_FAILURE);
+    throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
   }
   if (err.name === 'ParseError') {
     logger.debug({ err }, '');
-    throw new Error(PLATFORM_FAILURE);
+    throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
   }
   if (err.statusCode >= 500 && err.statusCode < 600) {
     logger.debug({ err }, 'GitHub failure: 5xx');
-    throw new Error(PLATFORM_FAILURE);
+    throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
   }
   if (
     err.statusCode === 403 &&
@@ -106,7 +106,7 @@ export function handleGotError(
       'GitHub failure: Bad credentials'
     );
     if (rateLimit === '60') {
-      throw new Error(PLATFORM_FAILURE);
+      throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
     }
     throw new Error(PLATFORM_BAD_CREDENTIALS);
   }
@@ -123,7 +123,7 @@ export function handleGotError(
       throw new Error(REPOSITORY_CHANGED);
     }
     logger.debug({ err }, '422 Error thrown from GitHub');
-    throw new Error(PLATFORM_FAILURE);
+    throw new ExternalHostError(err, PLATFORM_TYPE_GITHUB);
   }
   if (err.statusCode === 404) {
     logger.debug({ url: err.url }, 'GitHub 404');
diff --git a/lib/util/http/gitlab.ts b/lib/util/http/gitlab.ts
index 9a5d0f160509da53281bd33b21395a60fdfc493d..5e759d333952b2960b8e7053aabdf275775886d1 100644
--- a/lib/util/http/gitlab.ts
+++ b/lib/util/http/gitlab.ts
@@ -1,8 +1,8 @@
 import { URL } from 'url';
 import parseLinkHeader from 'parse-link-header';
-import { PLATFORM_FAILURE } from '../../constants/error-messages';
 import { PLATFORM_TYPE_GITLAB } from '../../constants/platforms';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { Http, HttpResponse, InternalHttpOptions } from '.';
 
 let baseUrl = 'https://gitlab.com/api/v4/';
@@ -63,7 +63,7 @@ export class GitlabHttp extends Http<GitlabHttpOptions, GitlabHttpOptions> {
         err.statusCode === 429 ||
         (err.statusCode >= 500 && err.statusCode < 600)
       ) {
-        throw new Error(PLATFORM_FAILURE);
+        throw new ExternalHostError(err, PLATFORM_TYPE_GITLAB);
       }
       const platformFailureCodes = [
         'EAI_AGAIN',
@@ -72,10 +72,10 @@ export class GitlabHttp extends Http<GitlabHttpOptions, GitlabHttpOptions> {
         'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
       ];
       if (platformFailureCodes.includes(err.code)) {
-        throw new Error(PLATFORM_FAILURE);
+        throw new ExternalHostError(err, PLATFORM_TYPE_GITLAB);
       }
       if (err.name === 'ParseError') {
-        throw new Error(PLATFORM_FAILURE);
+        throw new ExternalHostError(err, PLATFORM_TYPE_GITLAB);
       }
       throw err;
     }
diff --git a/lib/workers/branch/index.ts b/lib/workers/branch/index.ts
index 31963c57719a7c64007df942d4d261d424d3ea8c..a646d6dc708264257594733be2cbe59cd96783b3 100644
--- a/lib/workers/branch/index.ts
+++ b/lib/workers/branch/index.ts
@@ -4,11 +4,9 @@ import { DateTime } from 'luxon';
 import minimatch from 'minimatch';
 import { RenovateConfig } from '../../config';
 import {
-  DATASOURCE_FAILURE,
   MANAGER_LOCKFILE_ERROR,
   PLATFORM_AUTHENTICATION_ERROR,
   PLATFORM_BAD_CREDENTIALS,
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_CHANGED,
@@ -24,6 +22,7 @@ import { logger } from '../../logger';
 import { getAdditionalFiles } from '../../manager/npm/post-update';
 import { platform } from '../../platform';
 import { BranchStatus } from '../../types';
+import { ExternalHostError } from '../../types/error';
 import { emojify } from '../../util/emoji';
 import { exec } from '../../util/exec';
 import { readLocalFile, writeLocalFile } from '../../util/fs';
@@ -541,10 +540,7 @@ export async function processBranch(
       err.message.includes('fatal: Authentication failed')
     ) {
       throw new Error(PLATFORM_AUTHENTICATION_ERROR);
-    } else if (
-      err.message !== DATASOURCE_FAILURE &&
-      err.message !== PLATFORM_FAILURE
-    ) {
+    } else if (!(err instanceof ExternalHostError)) {
       logger.error({ err }, `Error updating branch: ${err.message}`);
     }
     // Don't throw here - we don't want to stop the other renovations
@@ -655,11 +651,8 @@ export async function processBranch(
     }
   } catch (err) /* istanbul ignore next */ {
     if (
-      [
-        PLATFORM_RATE_LIMIT_EXCEEDED,
-        PLATFORM_FAILURE,
-        REPOSITORY_CHANGED,
-      ].includes(err.message)
+      err instanceof ExternalHostError ||
+      [PLATFORM_RATE_LIMIT_EXCEEDED, REPOSITORY_CHANGED].includes(err.message)
     ) {
       logger.debug('Passing PR error up');
       throw err;
diff --git a/lib/workers/pr/index.ts b/lib/workers/pr/index.ts
index 9fc7e586e968ca317c0012d29635ace5dbfdea53..17c2bcdca22108d2d1cc8e91c3d269db56c96b3a 100644
--- a/lib/workers/pr/index.ts
+++ b/lib/workers/pr/index.ts
@@ -2,7 +2,6 @@ import sampleSize from 'lodash/sampleSize';
 import uniq from 'lodash/uniq';
 import { RenovateConfig } from '../../config/common';
 import {
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_CHANGED,
@@ -10,6 +9,7 @@ import {
 import { logger } from '../../logger';
 import { PlatformPrOptions, Pr, platform } from '../../platform';
 import { BranchStatus } from '../../types';
+import { ExternalHostError } from '../../types/error';
 import { BranchConfig, PrResult } from '../common';
 import { getPrBody } from './body';
 import { ChangeLogError } from './changelog';
@@ -427,9 +427,9 @@ export async function ensurePr(
   } catch (err) {
     // istanbul ignore if
     if (
+      err instanceof ExternalHostError ||
       err.message === REPOSITORY_CHANGED ||
       err.message === PLATFORM_RATE_LIMIT_EXCEEDED ||
-      err.message === PLATFORM_FAILURE ||
       err.message === PLATFORM_INTEGRATION_UNAUTHORIZED
     ) {
       logger.debug('Passing error up');
diff --git a/lib/workers/repository/error.spec.ts b/lib/workers/repository/error.spec.ts
index f0b10e9548f98ec641c550c1f3a7ea9031c31199..5fce970db9260a6f3ba513ffd160483124a545aa 100644
--- a/lib/workers/repository/error.spec.ts
+++ b/lib/workers/repository/error.spec.ts
@@ -1,12 +1,11 @@
 import { RenovateConfig, getConfig } from '../../../test/util';
 import {
   CONFIG_VALIDATION,
-  DATASOURCE_FAILURE,
+  EXTERNAL_HOST_ERROR,
   MANAGER_LOCKFILE_ERROR,
   MANAGER_NO_PACKAGE_FILES,
   PLATFORM_AUTHENTICATION_ERROR,
   PLATFORM_BAD_CREDENTIALS,
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_ACCESS_FORBIDDEN,
@@ -27,7 +26,7 @@ import {
   SYSTEM_INSUFFICIENT_MEMORY,
   UNKNOWN_ERROR,
 } from '../../constants/error-messages';
-import { DatasourceError } from '../../datasource/common';
+import { ExternalHostError } from '../../types/error';
 import handleError from './error';
 
 jest.mock('./error-config');
@@ -48,7 +47,6 @@ describe('workers/repository/error', () => {
       REPOSITORY_FORKED,
       MANAGER_NO_PACKAGE_FILES,
       CONFIG_VALIDATION,
-      DATASOURCE_FAILURE,
       REPOSITORY_ARCHIVED,
       REPOSITORY_MIRRORED,
       REPOSITORY_RENAMED,
@@ -60,7 +58,6 @@ describe('workers/repository/error', () => {
       MANAGER_LOCKFILE_ERROR,
       SYSTEM_INSUFFICIENT_DISK_SPACE,
       SYSTEM_INSUFFICIENT_MEMORY,
-      PLATFORM_FAILURE,
       REPOSITORY_NO_VULNERABILITY,
       REPOSITORY_CANNOT_FORK,
       PLATFORM_INTEGRATION_UNAUTHORIZED,
@@ -73,23 +70,26 @@ describe('workers/repository/error', () => {
         expect(res).toEqual(err);
       });
     });
-    it(`handles DatasourceError`, async () => {
-      const res = await handleError(config, new DatasourceError(new Error()));
-      expect(res).toEqual(DATASOURCE_FAILURE);
+    it(`handles ExternalHostError`, async () => {
+      const res = await handleError(
+        config,
+        new ExternalHostError(new Error(), 'some-host-type')
+      );
+      expect(res).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('rewrites git 5xx error', async () => {
       const gitError = new Error(
         "fatal: unable to access 'https://**redacted**@gitlab.com/learnox/learnox.git/': The requested URL returned error: 500\n"
       );
       const res = await handleError(config, gitError);
-      expect(res).toEqual(PLATFORM_FAILURE);
+      expect(res).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('rewrites git remote error', async () => {
       const gitError = new Error(
         'fatal: remote error: access denied or repository not exported: /b/nw/bd/27/47/159945428/108610112.git\n'
       );
       const res = await handleError(config, gitError);
-      expect(res).toEqual(PLATFORM_FAILURE);
+      expect(res).toEqual(EXTERNAL_HOST_ERROR);
     });
     it('handles unknown error', async () => {
       const res = await handleError(config, new Error('abcdefg'));
diff --git a/lib/workers/repository/error.ts b/lib/workers/repository/error.ts
index 48f8e7a911a9afa4da53887182cab59ca7655bc0..5ff14d0aeac259bfc6737f8bf10e0f95f0f2c5b2 100644
--- a/lib/workers/repository/error.ts
+++ b/lib/workers/repository/error.ts
@@ -2,12 +2,11 @@ import { RenovateConfig } from '../../config';
 
 import {
   CONFIG_VALIDATION,
-  DATASOURCE_FAILURE,
+  EXTERNAL_HOST_ERROR,
   MANAGER_LOCKFILE_ERROR,
   MANAGER_NO_PACKAGE_FILES,
   PLATFORM_AUTHENTICATION_ERROR,
   PLATFORM_BAD_CREDENTIALS,
-  PLATFORM_FAILURE,
   PLATFORM_INTEGRATION_UNAUTHORIZED,
   PLATFORM_RATE_LIMIT_EXCEEDED,
   REPOSITORY_ACCESS_FORBIDDEN,
@@ -28,8 +27,8 @@ import {
   SYSTEM_INSUFFICIENT_MEMORY,
   UNKNOWN_ERROR,
 } from '../../constants/error-messages';
-import { DatasourceError } from '../../datasource/common';
 import { logger } from '../../logger';
+import { ExternalHostError } from '../../types/error';
 import { raiseConfigWarningIssue } from './error-config';
 
 export default async function handleError(
@@ -107,22 +106,12 @@ export default async function handleError(
     await raiseConfigWarningIssue(config, err);
     return err.message;
   }
-  if (err instanceof DatasourceError) {
+  if (err instanceof ExternalHostError) {
     logger.warn(
-      { datasource: err.datasource, lookupName: err.lookupName, err: err.err },
-      'Datasource failure'
+      { hostType: err.hostType, lookupName: err.lookupName, err: err.err },
+      'Host error'
     );
-    logger.info('Registry error - skipping');
-    delete config.branchList; // eslint-disable-line no-param-reassign
-    return err.message;
-  }
-  if (err.message === DATASOURCE_FAILURE) {
-    logger.info({ err }, 'Registry error - skipping');
-    delete config.branchList; // eslint-disable-line no-param-reassign
-    return err.message;
-  }
-  if (err.message === PLATFORM_FAILURE) {
-    logger.info('Platform error - skipping');
+    logger.info('External host error causing abort - skipping');
     delete config.branchList; // eslint-disable-line no-param-reassign
     return err.message;
   }
@@ -174,7 +163,7 @@ export default async function handleError(
     logger.warn({ err }, 'Git error - aborting');
     delete config.branchList; // eslint-disable-line no-param-reassign
     // rewrite this error
-    return PLATFORM_FAILURE;
+    return EXTERNAL_HOST_ERROR;
   }
   if (
     err.message.includes('The remote end hung up unexpectedly') ||
@@ -183,7 +172,7 @@ export default async function handleError(
     logger.warn({ err }, 'Git error - aborting');
     delete config.branchList; // eslint-disable-line no-param-reassign
     // rewrite this error
-    return PLATFORM_FAILURE;
+    return EXTERNAL_HOST_ERROR;
   }
   // Swallow this error so that other repositories can be processed
   logger.error({ err }, `Repository has unknown error`);
diff --git a/lib/workers/repository/init/config.ts b/lib/workers/repository/init/config.ts
index 547c2b39335b7bb3c81b06e8dfac9bf6b1efa93c..21ce3d73254720483c290f5f43a824c926b97c49 100644
--- a/lib/workers/repository/init/config.ts
+++ b/lib/workers/repository/init/config.ts
@@ -7,13 +7,11 @@ import { configFileNames } from '../../../config/app-strings';
 import { decryptConfig } from '../../../config/decrypt';
 import { migrateAndValidate } from '../../../config/migrate-validate';
 import * as presets from '../../../config/presets';
-import {
-  CONFIG_VALIDATION,
-  PLATFORM_FAILURE,
-} from '../../../constants/error-messages';
+import { CONFIG_VALIDATION } from '../../../constants/error-messages';
 import * as npmApi from '../../../datasource/npm';
 import { logger } from '../../../logger';
 import { platform } from '../../../platform';
+import { ExternalHostError } from '../../../types/error';
 import { readLocalFile } from '../../../util/fs';
 import * as hostRules from '../../../util/host-rules';
 import { flattenPackageRules } from './flatten';
@@ -59,7 +57,10 @@ export async function mergeRenovateConfig(
     // istanbul ignore if
     if (renovateConfig === null) {
       logger.warn('Fetching renovate config returns null');
-      throw new Error(PLATFORM_FAILURE);
+      throw new ExternalHostError(
+        Error('Fetching renovate config returns null'),
+        config.platform
+      );
     }
     // istanbul ignore if
     if (!renovateConfig.length) {