diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts
index b0a5b91c5735723d0b3c0c01858457fc056762f3..676e685d337ceb557372fde3655a229fef1ce8ad 100644
--- a/lib/modules/datasource/index.ts
+++ b/lib/modules/datasource/index.ts
@@ -8,7 +8,6 @@ import * as packageCache from '../../util/cache/package';
 import { clone } from '../../util/clone';
 import { filterMap } from '../../util/filter-map';
 import { regEx } from '../../util/regex';
-import { Result } from '../../util/result';
 import { trimTrailingSlash } from '../../util/url';
 import { defaultVersioning } from '../versioning';
 import * as allVersioning from '../versioning';
@@ -506,12 +505,6 @@ export async function getPkgReleases(
   return res;
 }
 
-export function getPkgReleasesSafe(
-  config: GetPkgReleasesConfig
-): Promise<Result<ReleaseResult | null>> {
-  return Result.wrap(getPkgReleases(config));
-}
-
 export function supportsDigests(datasource: string | undefined): boolean {
   const ds = !!datasource && getDatasourceFor(datasource);
   return !!ds && 'getDigest' in ds;
diff --git a/lib/util/result.spec.ts b/lib/util/result.spec.ts
index 74d79451747e3da94338651e6397e6f4dafb5661..c25d8c2049931c5bf1146d081650d078aa3b05db 100644
--- a/lib/util/result.spec.ts
+++ b/lib/util/result.spec.ts
@@ -3,50 +3,45 @@ import { Result } from './result';
 describe('util/result', () => {
   describe('ok', () => {
     it('constructs successful result from value', () => {
-      expect(Result.ok(42).value()).toBe(42);
+      expect(Result.ok(42).value).toBe(42);
     });
   });
 
   describe('err', () => {
-    it('constructs error result', () => {
+    it('constructs `true` error by default', () => {
       const res = Result.err();
-      expect(res.error()).toEqual(new Error());
-    });
-
-    it('constructs error result from string', () => {
-      const res = Result.err('oops');
-      expect(res.error()?.message).toBe('oops');
+      expect(res.error).toBeTrue();
     });
 
     it('constructs error result from Error instance', () => {
       const err = new Error('oops');
       const res = Result.err(err);
-      expect(res.error()).toBe(err);
+      expect(res.error).toBe(err);
     });
   });
 
   describe('wrap', () => {
     it('wraps function returning successful result', () => {
       const res = Result.wrap(() => 42);
-      expect(res.value()).toBe(42);
+      expect(res.value).toBe(42);
     });
 
     it('wraps function that throws an error', () => {
       const res = Result.wrap(() => {
         throw new Error('oops');
       });
-      expect(res.error()?.message).toBe('oops');
+      expect(res.error?.message).toBe('oops');
     });
 
     it('wraps promise resolving to value', async () => {
       const res = await Result.wrap(Promise.resolve(42));
-      expect(res.value()).toBe(42);
+      expect(res.value).toBe(42);
     });
 
     it('wraps promise rejecting with error', async () => {
       const err = new Error('oops');
       const res = await Result.wrap(Promise.reject(err));
-      expect(res.error()?.message).toBe('oops');
+      expect(res.error?.message).toBe('oops');
     });
   });
 
@@ -61,59 +56,47 @@ describe('util/result', () => {
     it('no-op for error result', () => {
       const err = new Error('bar');
       const res = Result.err(err).transform(fn);
-      expect(res.value()).toBeUndefined();
-      expect(res.error()).toBe(err);
+      expect(res.value).toBeUndefined();
+      expect(res.error).toBe(err);
     });
   });
 
-  describe('unwrap', () => {
-    it('unwraps successful result', () => {
+  describe('catch', () => {
+    it('returns original value for successful result', () => {
       const res = Result.ok(42);
-      expect(res.unwrap()).toEqual({ ok: true, value: 42 });
-    });
-
-    it('unwraps error result with fallback value', () => {
-      const err = new Error('oops');
-      const res = Result.err(err);
-      expect(res.unwrap(42)).toEqual({ ok: true, value: 42 });
+      expect(res.catch(0)).toBe(42);
     });
 
-    it('unwraps error result', () => {
+    it('returns fallback value for error result', () => {
       const err = new Error('oops');
       const res = Result.err(err);
-      expect(res.unwrap()).toEqual({ ok: false, error: err });
+      expect(res.catch(42)).toBe(42);
     });
   });
 
   describe('value', () => {
     it('returns successful value', () => {
       const res = Result.ok(42);
-      expect(res.value()).toBe(42);
-    });
-
-    it('returns fallback value for error result', () => {
-      const err = new Error('oops');
-      const res = Result.err(err);
-      expect(res.value(42)).toBe(42);
+      expect(res.value).toBe(42);
     });
 
     it('returns undefined value for error result', () => {
       const err = new Error('oops');
       const res = Result.err(err);
-      expect(res.value()).toBeUndefined();
+      expect(res.value).toBeUndefined();
     });
   });
 
   describe('error', () => {
     it('returns undefined error for successful result', () => {
       const res = Result.ok(42);
-      expect(res.error()).toBeUndefined();
+      expect(res.error).toBeUndefined();
     });
 
     it('returns error for non-successful result', () => {
       const err = new Error('oops');
       const res = Result.err(err);
-      expect(res.error()).toEqual(err);
+      expect(res.error).toEqual(err);
     });
   });
 });
diff --git a/lib/util/result.ts b/lib/util/result.ts
index ae6dcf917a0c7ca86500a3b8504d7ea350fb0bd5..358c30fc8eef6d172406466f8f97f7730d028cff 100644
--- a/lib/util/result.ts
+++ b/lib/util/result.ts
@@ -1,33 +1,29 @@
 interface Ok<T> {
-  ok: true;
-  value: T;
+  readonly success: true;
+  readonly value: T;
 }
 
-interface Err {
-  ok: false;
-  error: Error;
+interface Err<E> {
+  readonly success: false;
+  readonly error: E;
 }
 
-type Res<T> = Ok<T> | Err;
+type Res<T, E> = Ok<T> | Err<E>;
 
-export class Result<T> {
-  static ok<T>(value: T): Result<T> {
-    return new Result({ ok: true, value });
+export class Result<T, E = Error> {
+  static ok<T>(value: T): Result<T, never> {
+    return new Result({ success: true, value });
   }
 
-  static err(): Result<never>;
-  static err(error: Error): Result<never>;
-  static err(message: string): Result<never>;
-  static err(error?: Error | string): Result<never> {
-    if (typeof error === 'undefined') {
-      return new Result({ ok: false, error: new Error() });
+  static err(): Result<never, true>;
+  static err<E>(e: E): Result<never, E>;
+  static err<E>(e?: E): Result<never, E> | Result<never, true> {
+    if (typeof e === 'undefined' && arguments.length === 0) {
+      return new Result({ success: false, error: true });
     }
 
-    if (typeof error === 'string') {
-      return new Result({ ok: false, error: new Error(error) });
-    }
-
-    return new Result({ ok: false, error });
+    const error = e as E;
+    return new Result({ success: false, error });
   }
 
   private static wrapCallback<T>(callback: () => T): Result<T> {
@@ -55,36 +51,23 @@ export class Result<T> {
       : Result.wrapCallback(input);
   }
 
-  private constructor(private res: Res<T>) {}
+  private constructor(public readonly res: Res<T, E>) {}
 
-  transform<U>(fn: (value: T) => U): Result<U> {
-    return this.res.ok
+  transform<U>(fn: (value: T) => U): Result<U, E> {
+    return this.res.success
       ? Result.ok(fn(this.res.value))
       : Result.err(this.res.error);
   }
 
-  unwrap(): Res<T>;
-  unwrap<U>(fallback: U): Res<T | U>;
-  unwrap<U>(fallback?: U): Res<T | U> {
-    if (this.res.ok) {
-      return this.res;
-    }
-
-    if (arguments.length) {
-      return { ok: true, value: fallback as U };
-    }
-
-    return this.res;
+  catch<U>(fallback: U): T | U {
+    return this.res.success ? this.res.value : fallback;
   }
 
-  value(): T | undefined;
-  value<U>(fallback: U): T | U;
-  value<U>(fallback?: U): T | U | undefined {
-    const res = arguments.length ? this.unwrap(fallback as U) : this.unwrap();
-    return res.ok ? res.value : undefined;
+  get value(): T | undefined {
+    return this.res.success ? this.res.value : undefined;
   }
 
-  error(): Error | undefined {
-    return this.res.ok ? undefined : this.res.error;
+  get error(): E | undefined {
+    return this.res.success ? undefined : this.res.error;
   }
 }
diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts
index 8c276343c4cbf17ce332614fa87532feb947b6c1..744249060e42d35e5ed44e2b6763ecd650c4f605 100644
--- a/lib/workers/repository/process/lookup/index.ts
+++ b/lib/workers/repository/process/lookup/index.ts
@@ -9,7 +9,7 @@ import {
   getDatasourceList,
   getDefaultVersioning,
   getDigest,
-  getPkgReleasesSafe,
+  getPkgReleases,
   isGetPkgReleasesConfig,
   supportsDigests,
 } from '../../../../modules/datasource';
@@ -19,6 +19,7 @@ import { ExternalHostError } from '../../../../types/errors/external-host-error'
 import { clone } from '../../../../util/clone';
 import { applyPackageRules } from '../../../../util/package-rules';
 import { regEx } from '../../../../util/regex';
+import { Result } from '../../../../util/result';
 import { getBucket } from './bucket';
 import { getCurrentVersion } from './current';
 import { filterVersions } from './filter';
@@ -82,8 +83,8 @@ export async function lookupUpdates(
         res.skipReason = 'is-pinned';
         return res;
       }
-      const lookupResult = (await getPkgReleasesSafe(config)).unwrap();
-      if (!lookupResult.ok) {
+      const { res: lookupResult } = await Result.wrap(getPkgReleases(config));
+      if (!lookupResult.success) {
         throw lookupResult.error;
       }
       dependency = clone(lookupResult.value);