Skip to content
Meeko
Type to search the guides and the API reference. Open it from any page with / or Ctrl K; move with the arrow keys and open a result with Enter.
Get started

Contents

On this page

SessionRevokedError

The 401 SESSION_REVOKED ApiError for a session revoked, rotated or expired during the request, and the abort reason of context.signal.

server Since 1.0.0 @meekojs/meeko/server Source code
ts
import { SessionRevokedError } from "@meekojs/meeko/server";

SessionRevokedError is an ApiError with code SESSION_REVOKED and status 401. Meeko uses it in two places:

  • context.session.verify() throws it if the request's session was revoked, replaced by rotation or expired since it was read;
  • context.session.signal, and with it context.signal, is aborted with it when another request or instance revokes that session's family.

If it escapes an API or RPC handler, the response is 401 {"code":"SESSION_REVOKED", …}; in the browser it arrives as a ClientError with that code.

Usage#

ts
// server/api/orders/[id]/pay.post.ts
import { SessionRevokedError } from "@meekojs/meeko/server";

export default defineApiRoute({
  auth: "required",
  params: orderParams,
  response: okResult,
  handler: async ({ params, context }) => {
    try {
      await context.session.verify();
      await payments.charge(params.id, { signal: context.signal });
    } catch (error) {
      if (error instanceof SessionRevokedError) console.warn("session revoked before charging", context.requestId);
      throw error; // 401 SESSION_REVOKED
    }
    return { ok: true as const };
  },
});

Type#

ts
class SessionRevokedError extends ApiError {
  constructor();
}

Parameters#

new SessionRevokedError() takes no arguments. It inherits from ApiError:

Property Value
code "SESSION_REVOKED"
status 401
message "Session revoked" (internal; not sent to the client)
name "SessionRevokedError"

Return value#

An Error that is also an ApiError. errorResponse converts it into 401 with {"code":"SESSION_REVOKED","status":401,"requestId":"…"}.

Examples#

Cancel long-running work for a revoked session#

ts
handler: async ({ context }) => {
  // context.signal is aborted if the client leaves or another tab logs out.
  const report = await fetch("https://reports.internal/generate", { method: "POST", signal: context.signal });
  return report.json();
},

If the family is revoked midway, fetch rejects with the abort reason, a SessionRevokedError, and the response is 401.

Distinguish the reason for an abort#

ts
import { SessionRevokedError } from "@meekojs/meeko/server";

export function abortReason(signal: AbortSignal): "revoked" | "client" | "none" {
  if (!signal.aborted) return "none";
  return signal.reason instanceof SessionRevokedError ? "revoked" : "client";
}

Send the browser to sign-in#

ts
// mountClientApp's onError, or an application plugin's.
import { isClientError } from "@meekojs/meeko/framework";

export function onError(error: unknown): void {
  if (isClientError(error, "SESSION_REVOKED") || isClientError(error, "UNAUTHENTICATED")) location.assign("/login");
}

Common mistakes#

Catch it and continue#

Incorrectts
try { await context.session.verify(); } catch { /* continue */ }
await payments.charge(order);

The charge is made using a session that is no longer valid. verify() exists to stop execution before an irreversible side effect.

Correctts
await context.session.verify(); // if it throws, the response is 401 and no charge is made
await payments.charge(order);

Ignore context.signal#

Incorrectts
const rows = await db.query(longReportSql); // without a signal

There is no error: revocation aborts the signal, but aborting is cooperative and code that does not observe it continues to completion.

Correctts
const rows = await db.query(longReportSql, { signal: context.signal });

Notes#

  • Server. Import it from @meekojs/meeko/server. On the client, check with isClientError(error, "SESSION_REVOKED").
  • Across instances. Aborting a request in another instance requires a store with subscribeRevocations (RedisSessionStore with subscriber). With SQL or D1, only verify() and the next read detect it.
  • Socket. Connections in a revoked family close with 1008 (“Session revoked”), without waiting for another event.
  • The revoking request. revoke() does not abort its own request, because it must send the empty cookie.
  • Only 4xx. A 401 is an expected response: it does not reach the runtime's onError.

Was this page helpful?

Add a comment

It is sent when you choose “Yes” or “No”. Only the page, your answer and the comment are stored: no cookies and no personal data.

0 of 2000 characters

Edit on GitHub: docs/en/reference/server/sessionrevokederror.md