TypeError: Cannot read property 'then' of undefined in FeathersJS service methods
0 reputation · 07 Jun 2024, 05:47 UTC
0 reputation · 07 Jun 2024, 05:47 UTC
FeathersJS v5 requires every service method to return a Promise. If a method returns a non‑promise value, the framework throws TypeError: Cannot read property 'then' of undefined. Under concurrent load, synchronous hooks can block the event loop, causing latency spikes that appear only when many requests pile up.
While the docs recommend keeping hooks asynchronous and offloading heavy work to background jobs, there is no built‑in mechanism to detect or prevent event‑loop blocking at runtime. Developers must manually refactor synchronous hooks or add external rate‑limiting, but the optimal strategy for balancing real‑time channel updates with background job offloading remains unclear.
35275 reputation · 07 Jun 2024, 10:34 UTC
The TypeError: Cannot read property 'then' of undefined happens because Feathers internally calls .then() on whatever each service method (or a hook that overwrites the result) returns. If any method returns undefined or a plain value, that internal call blows up. The fix for the error itself is mechanical: declare every service method and hook async, and make sure no code path falls through without a return. The harder part of your question — guaranteeing this app-wide, finding blocking hooks, and offloading work without breaking real-time channels — is addressed below.
The most common concrete cause is a custom method that does synchronous work or forgets a return, so it implicitly yields undefined. Two layers of protection work well:
.then function. In production you can defensively pass results through Promise.resolve(), but be aware this only masks the TypeError — it does nothing about the synchronous work that usually accompanies it.// Dev-only around hook: flag non-promise results
app.hooks({
around: {
all: [
async (context, next) => {
await next();
const r = context.result;
if (r !== undefined && typeof r?.then !== 'function' && !Array.isArray(r) && typeof r !== 'object') {
console.warn(`Non-promise-ish result: ${context.path}.${context.method}`);
}
}
]
}
});
Hook APIs differ between Feathers v4 and v5 (around hooks and context properties changed), so confirm your installed version before adapting this snippet.
There is no built-in Feathers mechanism for this, but you can get solid signal without disrupting functionality:
perf_hooks.monitorEventLoopDelay() and log the 99th-percentile event-loop delay. This is process-wide, so it tells you that blocking happens, not where.performance.now()) before await next() and after it, per method. Under load, correlate lag spikes with the methods showing large gaps — those contain your synchronous culprits (callback-style DB drivers, JSON parsing of huge payloads, crypto, etc.).The pattern that preserves channels is: the service method enqueues a job (e.g., BullMQ on Redis) and returns immediately; a separate worker process performs the heavy work, then makes a normal lightweight service call (create/patch) or emits through app.service(...).emit(). Because that final call flows through the standard Feathers event pipeline, channel publishing works exactly as it does for client-originated calls — provided the worker shares the same app/channel configuration. Design job handlers to be idempotent, since queues give at-least-once delivery.
If you can share the stack trace's top frame, it will name the exact method returning undefined — that changes this from a general hardening exercise into a one-line fix. Otherwise, run the dev hook above once; it identifies the offender in minutes.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.