diff --git a/lib/logger/__mocks__/index.ts b/lib/logger/__mocks__/index.ts
index 1448ced57b093d19db13bd71dce1212760768628..637c95b8cd85e57bcd1dbfe67842454a7594b50c 100644
--- a/lib/logger/__mocks__/index.ts
+++ b/lib/logger/__mocks__/index.ts
@@ -20,6 +20,6 @@ export const addMeta = jest.fn();
 export const removeMeta = jest.fn();
 export const levels = jest.fn();
 export const addStream = jest.fn();
-export const getErrors = (): any[] => [];
+export const getProblems = jest.fn((): any[] => []);
 
 export { logger };
diff --git a/lib/logger/__snapshots__/index.spec.ts.snap b/lib/logger/__snapshots__/index.spec.ts.snap
index 2390af8dcaae0cafc1a92a5a9e01ef32b54b515e..281280bb59c76a86596da2dd20df84edaa6884d7 100644
--- a/lib/logger/__snapshots__/index.spec.ts.snap
+++ b/lib/logger/__snapshots__/index.spec.ts.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`logger saves errors 1`] = `
+exports[`logger saves problems 1`] = `
 Array [
   Object {
     "any": "test",
@@ -15,6 +15,7 @@ Array [
     "logContext": "abc123",
     "msg": "",
     "name": "renovate",
+    "password": "***********",
     "some": "meta",
   },
   Object {
@@ -25,5 +26,12 @@ Array [
     "name": "renovate",
     "some": "meta",
   },
+  Object {
+    "any": "test",
+    "level": 40,
+    "logContext": "abc123",
+    "msg": "a warning with a **redacted**",
+    "name": "renovate",
+  },
 ]
 `;
diff --git a/lib/logger/index.spec.ts b/lib/logger/index.spec.ts
index cc2c029d5d19dd2dfdf9b4ad8ca5515ff227c94f..79f599a06199b2fde59ec7b80e2bdb2132221e15 100644
--- a/lib/logger/index.spec.ts
+++ b/lib/logger/index.spec.ts
@@ -1,11 +1,12 @@
 import _fs from 'fs-extra';
 import { add } from '../util/host-rules';
+import { add as addSecret } from '../util/sanitize';
 import {
   addMeta,
   addStream,
-  clearErrors,
+  clearProblems,
   getContext,
-  getErrors,
+  getProblems,
   levels,
   logger,
   removeMeta,
@@ -52,14 +53,17 @@ describe('logger', () => {
     expect(() => levels('stdout', 'debug')).not.toThrow();
   });
 
-  it('saves errors', () => {
+  it('saves problems', () => {
+    addSecret('p4$$w0rd');
     levels('stdout', 'fatal');
     logger.error('some meta');
-    logger.error({ some: 'meta' });
+    logger.error({ some: 'meta', password: 'super secret' });
     logger.error({ some: 'meta' }, 'message');
-    expect(getErrors()).toMatchSnapshot();
-    clearErrors();
-    expect(getErrors()).toHaveLength(0);
+    logger.warn('a warning with a p4$$w0rd');
+    logger.info('ignored');
+    expect(getProblems()).toMatchSnapshot();
+    clearProblems();
+    expect(getProblems()).toHaveLength(0);
   });
 
   it('should contain path or stream parameters', () => {
diff --git a/lib/logger/index.ts b/lib/logger/index.ts
index 9ebba02304fa9255c070a1781a9bdac451e80cfe..9e06d13b33ccdf12de9bcfc8f8dd8f760c8aa487 100644
--- a/lib/logger/index.ts
+++ b/lib/logger/index.ts
@@ -6,7 +6,7 @@ import cmdSerializer from './cmd-serializer';
 import configSerializer from './config-serializer';
 import errSerializer from './err-serializer';
 import { RenovateStream } from './pretty-stdout';
-import { ErrorStream, withSanitizer } from './utils';
+import { BunyanRecord, ProblemStream, withSanitizer } from './utils';
 
 let logContext: string = process.env.LOG_CONTEXT || shortid.generate();
 let curMeta = {};
@@ -17,7 +17,7 @@ export interface LogError {
   msg?: string;
 }
 
-const errors = new ErrorStream();
+const problems = new ProblemStream();
 
 const stdout: bunyan.Stream = {
   name: 'stdout',
@@ -49,9 +49,9 @@ const bunyanLogger = bunyan.createLogger({
   streams: [
     stdout,
     {
-      name: 'error',
-      level: 'error' as bunyan.LogLevel,
-      stream: errors as any,
+      name: 'problems',
+      level: 'warn' as bunyan.LogLevel,
+      stream: problems as any,
       type: 'raw',
     },
   ].map(withSanitizer),
@@ -139,10 +139,10 @@ export function levels(name: string, level: bunyan.LogLevel): void {
   bunyanLogger.levels(name, level);
 }
 
-export function getErrors(): any {
-  return errors.getErrors();
+export function getProblems(): BunyanRecord[] {
+  return problems.getProblems();
 }
 
-export function clearErrors(): void {
-  return errors.clearErrors();
+export function clearProblems(): void {
+  return problems.clearProblems();
 }
diff --git a/lib/logger/utils.ts b/lib/logger/utils.ts
index d2208aba0cf4e1689f8a2a29b5b0abd7cfe4f4bb..4cf60954eb3502dc5debcc059c3359ff69225ef7 100644
--- a/lib/logger/utils.ts
+++ b/lib/logger/utils.ts
@@ -11,8 +11,8 @@ export interface BunyanRecord extends Record<string, any> {
 
 const excludeProps = ['pid', 'time', 'v', 'hostname'];
 
-export class ErrorStream extends Stream {
-  private _errors: BunyanRecord[] = [];
+export class ProblemStream extends Stream {
+  private _problems: BunyanRecord[] = [];
 
   readable: boolean;
 
@@ -25,20 +25,20 @@ export class ErrorStream extends Stream {
   }
 
   write(data: BunyanRecord): boolean {
-    const err = { ...data };
+    const problem = { ...data };
     for (const prop of excludeProps) {
-      delete err[prop];
+      delete problem[prop];
     }
-    this._errors.push(err);
+    this._problems.push(problem);
     return true;
   }
 
-  getErrors(): BunyanRecord[] {
-    return this._errors;
+  getProblems(): BunyanRecord[] {
+    return this._problems;
   }
 
-  clearErrors(): void {
-    this._errors = [];
+  clearProblems(): void {
+    this._problems = [];
   }
 }
 const templateFields = ['prBody'];
diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts
index b79eef90536cccf64c73cd307a2164d7f7da7322..f48ca89c306305cf912f4612a6f48fc90cf582b6 100644
--- a/lib/workers/global/index.spec.ts
+++ b/lib/workers/global/index.spec.ts
@@ -1,3 +1,5 @@
+import { ERROR, WARN } from 'bunyan';
+import { logger } from '../../../test/util';
 import * as _configParser from '../../config';
 import {
   PLATFORM_TYPE_GITHUB,
@@ -20,6 +22,7 @@ const limits = _limits;
 describe('lib/workers/global', () => {
   beforeEach(() => {
     jest.resetAllMocks();
+    logger.getProblems.mockImplementationOnce(() => []);
     configParser.parseConfigs = jest.fn();
     platform.initPlatform.mockImplementation((input) => Promise.resolve(input));
   });
@@ -77,7 +80,36 @@ describe('lib/workers/global', () => {
     expect(configParser.parseConfigs).toHaveBeenCalledTimes(1);
     expect(repositoryWorker.renovateRepository).toHaveBeenCalledTimes(0);
   });
-
+  it('exits with non-zero when errors are logged', async () => {
+    configParser.parseConfigs.mockResolvedValueOnce({
+      baseDir: '/tmp/base',
+      cacheDir: '/tmp/cache',
+      repositories: [],
+    });
+    logger.getProblems.mockReset();
+    logger.getProblems.mockImplementationOnce(() => [
+      {
+        level: ERROR,
+        msg: 'meh',
+      },
+    ]);
+    await expect(globalWorker.start()).resolves.not.toEqual(0);
+  });
+  it('exits with zero when warnings are logged', async () => {
+    configParser.parseConfigs.mockResolvedValueOnce({
+      baseDir: '/tmp/base',
+      cacheDir: '/tmp/cache',
+      repositories: [],
+    });
+    logger.getProblems.mockReset();
+    logger.getProblems.mockImplementationOnce(() => [
+      {
+        level: WARN,
+        msg: 'meh',
+      },
+    ]);
+    await expect(globalWorker.start()).resolves.toEqual(0);
+  });
   describe('processes platforms', () => {
     it('github', async () => {
       configParser.parseConfigs.mockResolvedValueOnce({
diff --git a/lib/workers/global/index.ts b/lib/workers/global/index.ts
index 6e353acf06fd8a89914b3ccc9c6ab87ec7790bcd..9a4260469c3d9343d636bc35795ffa1d257d2e92 100644
--- a/lib/workers/global/index.ts
+++ b/lib/workers/global/index.ts
@@ -1,8 +1,9 @@
 import path from 'path';
 import is from '@sindresorhus/is';
+import { ERROR } from 'bunyan';
 import fs from 'fs-extra';
 import * as configParser from '../../config';
-import { getErrors, logger, setMeta } from '../../logger';
+import { getProblems, logger, setMeta } from '../../logger';
 import { setUtilConfig } from '../../util';
 import * as hostRules from '../../util/host-rules';
 import * as repositoryWorker from '../repository';
@@ -76,8 +77,7 @@ export async function start(): Promise<0 | 1> {
     globalFinalize(config);
     logger.debug(`Renovate exiting`);
   }
-  const loggerErrors = getErrors();
-  /* istanbul ignore if */
+  const loggerErrors = getProblems().filter((p) => p.level >= ERROR);
   if (loggerErrors.length) {
     logger.info(
       { loggerErrors },
diff --git a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
index 41a7139fd43448f24f32d3ae22eb7775fd1559c9..735ce9523c3a6ecbe21354bc4e9927f6a5b0c0ae 100644
--- a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
+++ b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
@@ -1,5 +1,27 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`workers/repository/master-issue ensureMasterIssue() contains logged problems 1`] = `
+"This issue contains a list of Renovate updates and their statuses.
+
+## Repository problems
+
+These problems occurred while renovating this repository.
+
+ - ERROR: everything is broken
+ - WARN: just a bit
+ - ERROR: i am a duplicated problem
+ - ERROR: i am a non-duplicated problem
+ - WARN: i am a non-duplicated problem
+
+## Pending Status Checks
+
+These updates await pending status checks. To force their creation now, check the box below.
+
+ - [ ] <!-- approvePr-branch=branchName1 -->pr1
+
+"
+`;
+
 exports[`workers/repository/master-issue ensureMasterIssue() open or update Dependency Dashboard when all branches are closed and dependencyDashboardAutoclose is false 1`] = `
 "This issue contains a list of Renovate updates and their statuses.
 
diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts
index 08d2045db69e3df0cd378b5570371feb9a2ad545..b71cd8922d592d9df7764476017abbbc99f37eef 100644
--- a/lib/workers/repository/dependency-dashboard.spec.ts
+++ b/lib/workers/repository/dependency-dashboard.spec.ts
@@ -1,6 +1,12 @@
 import fs from 'fs';
+import { ERROR, WARN } from 'bunyan';
 import { mock } from 'jest-mock-extended';
-import { RenovateConfig, getConfig, platform } from '../../../test/util';
+import {
+  RenovateConfig,
+  getConfig,
+  logger,
+  platform,
+} from '../../../test/util';
 import { PLATFORM_TYPE_GITHUB } from '../../constants/platforms';
 import { Platform, Pr } from '../../platform';
 import { PrState } from '../../types';
@@ -15,7 +21,7 @@ type PrUpgrade = BranchUpgradeConfig;
 
 let config: RenovateConfig;
 beforeEach(() => {
-  jest.resetAllMocks();
+  jest.clearAllMocks();
   config = getConfig();
   config.platform = PLATFORM_TYPE_GITHUB;
   config.errors = [];
@@ -31,7 +37,7 @@ async function dryRun(
   getBranchPrCalls = 0,
   findPrCalls = 0
 ) {
-  jest.resetAllMocks();
+  jest.clearAllMocks();
   config.dryRun = true;
   await dependencyDashboard.ensureMasterIssue(config, branches);
   expect(platform.ensureIssueClosing).toHaveBeenCalledTimes(
@@ -423,5 +429,54 @@ describe('workers/repository/master-issue', () => {
       // same with dry run
       await dryRun(branches, platform);
     });
+
+    it('contains logged problems', async () => {
+      const branches: BranchConfig[] = [
+        {
+          ...mock<BranchConfig>(),
+          prTitle: 'pr1',
+          upgrades: [
+            { ...mock<PrUpgrade>(), depName: 'dep1', repository: 'repo1' },
+          ],
+          res: ProcessBranchResult.Pending,
+          branchName: 'branchName1',
+        },
+      ];
+      logger.getProblems.mockReturnValueOnce([
+        {
+          level: ERROR,
+          msg: 'everything is broken',
+        },
+        {
+          level: WARN,
+          msg: 'just a bit',
+        },
+        {
+          level: ERROR,
+          msg: 'i am a duplicated problem',
+        },
+        {
+          level: ERROR,
+          msg: 'i am a duplicated problem',
+        },
+        {
+          level: ERROR,
+          msg: 'i am a non-duplicated problem',
+        },
+        {
+          level: WARN,
+          msg: 'i am a non-duplicated problem',
+        },
+        {
+          level: WARN,
+          msg: 'i am an artifact error',
+          artifactErrors: {},
+        },
+      ]);
+      config.dependencyDashboard = true;
+      await dependencyDashboard.ensureMasterIssue(config, branches);
+      expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+      expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+    });
   });
 });
diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts
index 520ea837ee8444b13c208ddba85a9e0c71a83c5d..17769450bb5699aebd28c5f2877e25304ca055c5 100644
--- a/lib/workers/repository/dependency-dashboard.ts
+++ b/lib/workers/repository/dependency-dashboard.ts
@@ -1,6 +1,7 @@
 import is from '@sindresorhus/is';
+import { nameFromLevel } from 'bunyan';
 import { RenovateConfig } from '../../config';
-import { logger } from '../../logger';
+import { getProblems, logger } from '../../logger';
 import { Pr, platform } from '../../platform';
 import { PrState } from '../../types';
 import { BranchConfig, ProcessBranchResult } from '../common';
@@ -22,6 +23,31 @@ function getListItem(branch: BranchConfig, type: string, pr?: Pr): string {
   return item + ' (' + uniquePackages.join(', ') + ')\n';
 }
 
+function appendRepoProblems(config: RenovateConfig, issueBody: string): string {
+  let newIssueBody = issueBody;
+  const repoProblems = new Set(
+    getProblems()
+      .filter(
+        (problem) =>
+          problem.repository === config.repository && !problem.artifactErrors
+      )
+      .map(
+        (problem) =>
+          `${nameFromLevel[problem.level].toUpperCase()}: ${problem.msg}`
+      )
+  );
+  if (repoProblems.size) {
+    newIssueBody += '## Repository problems\n\n';
+    newIssueBody +=
+      'These problems occurred while renovating this repository.\n\n';
+    for (const repoProblem of repoProblems) {
+      newIssueBody += ` - ${repoProblem}\n`;
+    }
+    newIssueBody += '\n';
+  }
+  return newIssueBody;
+}
+
 export async function ensureMasterIssue(
   config: RenovateConfig,
   branches: BranchConfig[]
@@ -60,6 +86,9 @@ export async function ensureMasterIssue(
   if (config.dependencyDashboardHeader?.length) {
     issueBody += `${config.dependencyDashboardHeader}\n\n`;
   }
+
+  issueBody = appendRepoProblems(config, issueBody);
+
   const pendingApprovals = branches.filter(
     (branch) => branch.res === ProcessBranchResult.NeedsApproval
   );
diff --git a/test/util.ts b/test/util.ts
index 4dd6fe791c3aefd6486ce25443037de4df8903c0..844a7e74e2ce93d61251d5b26f8352a2531e60d5 100644
--- a/test/util.ts
+++ b/test/util.ts
@@ -2,6 +2,7 @@ import crypto from 'crypto';
 import { expect } from '@jest/globals';
 import { RenovateConfig as _RenovateConfig } from '../lib/config';
 import { getConfig } from '../lib/config/defaults';
+import * as _logger from '../lib/logger';
 import { platform as _platform } from '../lib/platform';
 import * as _env from '../lib/util/exec/env';
 import * as _fs from '../lib/util/fs';
@@ -29,6 +30,7 @@ export const git = mocked(_git);
 export const platform = mocked(_platform);
 export const env = mocked(_env);
 export const hostRules = mocked(_hostRules);
+export const logger = mocked(_logger);
 
 // Required because of isolatedModules
 export type RenovateConfig = _RenovateConfig;