HeyPuter/puter · error · HttpError

not_found

not_found

Error message

User not found

What it means

Raised in `refreshUser` when the primary DB read (`getByProperty('id', ..., { force: true })`, deliberately bypassing cache) for the authenticated user's id returns no row. The actor was authenticated against a user that no longer exists in the store.

Source

Thrown at src/backend/core/http/middleware/userProtected.ts:172

    // 2. Fresh user row (bypass cache to catch just-suspended accounts).
    // `getById` doesn't take options; go through `getByProperty` with
    // `{ force: true }` to force a primary read.
    const refreshUser: RequestHandler = async (
        req: Request,
        _res: Response,
        next: NextFunction,
    ) => {
        const actor = req.actor;
        if (!actor?.user?.id)
            throw new HttpError(401, 'User required', {
                legacyCode: 'unauthorized',
            });
        const user = await userStore.getByProperty('id', actor.user.id, {
            force: true,
        });
        if (!user)
            throw new HttpError(404, 'User not found', {
                legacyCode: 'not_found',
            });
        if (user.suspended)
            throw new HttpError(403, 'Account is suspended', {
                legacyCode: 'account_suspended',
            });
        req.userProtected = { user };
        next();
    };

    // 3. Password (bcrypt) OR valid OIDC revalidation cookie.
    //
    //   - Temp users (no password + no email) pass only when the route was
    //     registered with `allowTempUsers: true` (delete-own-user).
    //   - `req.body.password` → bcrypt match against user row. OIDC-only
    //     accounts bounce with `oidc_revalidation_required` + a
    //     `revalidate_url` helper so the GUI can open the OIDC popup.
    //   - Otherwise accept a valid `puter_revalidation` cookie. Expiry,

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Sign out and re-authenticate / sign up again — the session is orphaned.
  2. If admin, inspect the user store for the missing id and reconcile.
  3. Do not reuse sessions after deleting the owning account.
Defensive patterns

Strategy: try-catch

Try / catch

try { await call(); }
catch (e) {
  if (e.code === 'not_found' && /user/i.test(e.message)) { logout(); routeToSignup(); return; }
  throw e;
}

Prevention

When it happens

Trigger: The account was deleted between authentication and the userProtected call; a data-inconsistency/restore left the actor referencing a dropped user; a test fixture was removed mid-flow.

Common situations: Concurrent account deletion while a session is still active; DB replication lag or a partial migration; a stale actor/token retained after deletion.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/5f8f5904ac957bdd. Report an issue: GitHub.