Skip to main content

Error handling

get(), set() and cacheObservable() throw on failure. Errors are typed classes living under the NcachedServiceErrors namespace, so you can use instanceof to discriminate cases.

For most read sites, prefer getOrDefault() — it's the built-in safe accessor, and you won't need any of the patterns on this page. This guide is for the cases where the typed errors do matter.

The five error types

ErrorThrown byMeaning
InsufficientsKeysProvidedErrorget, setFewer than two keys were passed
KeyNotFoundget, cacheObservableA namespace key in the path doesn't exist
MapNotFoundget, cacheObservableA key in the path exists but doesn't point to a Map
ValueNotFoundget, cacheObservableThe path is valid but the final key has no value, or the entry has expired
UncloneableValueErrorset, getThe value cannot be deep-cloned by structuredClone (typically a function, DOM node, or class instance with private fields)

All five extend the native Error and carry a descriptive message. UncloneableValueError additionally exposes the original platform error on its cause property.

cacheObservable() only surfaces these on the first subscription path before falling through to the source. Cache misses inside cacheObservable() are handled internally — they trigger a fetch, not a throw.

Importing the namespace

import { NcachedServiceErrors } from 'ng-ncached';

Discriminating with instanceof

import { NcachedService, NcachedServiceErrors } from 'ng-ncached';

try {
const value = this._cache.get<string>('users', 'currentName');
// ...use value
} catch (error) {
if (error instanceof NcachedServiceErrors.InsufficientsKeysProvidedError) {
// Programmer error — usually a bug, not a runtime condition.
console.error('Bad call to get():', error.message);
return;
}

if (error instanceof NcachedServiceErrors.KeyNotFound) {
// The whole namespace branch hasn't been seeded yet.
return;
}

if (error instanceof NcachedServiceErrors.MapNotFound) {
// A namespace exists at this key, but no Map has been created.
return;
}

if (error instanceof NcachedServiceErrors.ValueNotFound) {
// Cache miss for this specific entry, OR the entry has expired.
return;
}

if (error instanceof NcachedServiceErrors.UncloneableValueError) {
// The cached value couldn't be deep-cloned for return. Inspect error.cause for the underlying DataCloneError.
console.error('Uncloneable value:', error.message, error.cause);
return;
}

// Anything else is unexpected — re-throw.
throw error;
}

Distinguishing "expired" from "never seen"

ValueNotFound is thrown for both of these cases:

  • The key exists in the path but has no entry in the Map.
  • The entry exists but its expiresAt is in the past.

If you need to distinguish, do the check yourself before calling get():

import { ICacheEntry } from 'ng-ncached';

// Reach into the internal Map (use sparingly — relies on the wrapper shape).
function diagnoseMiss(cache: any, ...keys: string[]): 'never-seen' | 'expired' | 'present' {
// ...walk the cache and inspect ICacheEntry.expiresAt
}

In practice, getOrDefault() covers ~95 % of read sites and you don't need to make this distinction. If you do, prefer explicit invalidation (Invalidation) over inferring from errors.

Just need a boolean check?

Use the built-in has(...keys) — it returns true/false without throwing, and skips the deep clone that get() would perform:

if (this._cache.has('users', 'currentName')) {
// ...entry is present and not expired
}

What's next?