vercel/next.js · error · Error
`after()`: Argument must be a promise or a function
Error message
`after()`: Argument must be a promise or a function
What it means
Thrown by AfterContext.after() when the task argument is neither a thenable (Promise) nor a function. The after() API accepts only these two shapes so it can schedule deferred work after the response is sent. Passing any other type (number, object, string, undefined) is a programming error surfaced synchronously at the call site.
Source
Thrown at packages/next/src/server/after/after-context.ts:72
public after(task: AfterTask, workUnitStore: WorkUnitStore): void {
if (this.initialOnCloseError) {
throw new InvariantError(
`An onClose call failed, which means after() can't work correctly.`,
{ cause: this.initialOnCloseError.error }
)
}
// Save the workUnitStore so we can switch its phase later.
this.workUnitStores.add(workUnitStore)
if (isThenable(task)) {
this.addThenable(task)
} else if (typeof task === 'function') {
// TODO(after): implement tracing
this.addCallback(task, workUnitStore)
} else {
throw new Error('`after()`: Argument must be a promise or a function')
}
}
private addThenable(thenable: PromiseLike<any>) {
if (!this.waitUntil) {
errorWaitUntilNotAvailable()
}
this.waitUntil(
new Promise<void>((resolve) => {
thenable.then(
() => {
resolve()
},
(error) => {
resolve()
this.reportTaskError('promise', error)
}
)View on GitHub (pinned to 0ae8c72462)
Solutions
- Pass a function: after(() => { /* deferred work */ }).
- Or pass a Promise: after(someAsyncTask()).
- Add a TypeScript type annotation using AfterTask<T> so the compiler rejects invalid arguments before runtime.
Example fix
// before
after(undefined)
after({ log: 'done' })
// after
after(() => { console.log('done') })
after(sendAnalytics()) Defensive patterns
Strategy: type-guard
Validate before calling
function validateAfterTask(task: unknown) {
if (task !== null && (typeof task === 'function' || (typeof task === 'object' && typeof (task as any).then === 'function'))) return
throw new Error('after() requires a Promise or a function')
} Type guard
import type { AfterTask } from 'next/server'
function isAfterTask(t: unknown): t is AfterTask {
return typeof t === 'function' || (t != null && typeof (t as any).then === 'function')
} Prevention
- Type after() arguments with AfterTask<T> so the compiler checks them.
- Pass either an arrow function or an already-invoked async function's Promise.
- Never call after() with no argument or with a plain object.
When it happens
Trigger: Calling after(someValue) where someValue is not a Promise and not a function — e.g. after(undefined), after({ foo: 1 }), after(42), or after(null). The isThenable and typeof === 'function' checks both fail and the error is thrown.
Common situations: Forgetting to pass an argument; passing a callback's return value instead of the callback; passing an already-awaited result; refactor that changes the argument type.
Related errors
- `after` was called outside a request scope. Read more: https
- `after()` will not work correctly, because `waitUntil` is no
- Invalid redirect arguments. Please use a single argument URL
- Invalid urlPath provided to revalidate(), must be a path e.g
- Invalid --top value: ${topRaw}
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/14823b09d4b38e7f.
Report an issue: GitHub.