Mintplex-Labs/anything-llm · warning

Memory not found.

Error message

Memory not found.

What it means

404 from the validateMemoryOwner middleware. In multi-user mode the lookup adds clause.userId = user.id, so a memory owned by another user is deliberately indistinguishable from a missing one — both yield null from Memory.get and 404. Also fires for non-numeric ids (Number() → NaN never matches) and, subtly, when Memory.get swallows a DB error and returns null.

Source

Thrown at server/endpoints/memory.js:32

    return response.status(403).json({ error: "Personalization is disabled." });
  next();
}

/**
 * Loads the memory by :memoryId and, in multi-user mode, scopes the query to the requester's userId.
 * A memory owned by another user returns null here and is indistinguishable from "not found" — 404 either way.
 */
async function validateMemoryOwner(request, response, next) {
  try {
    const clause = { id: Number(request.params.memoryId) };
    if (response.locals.multiUserMode) {
      const user = await userFromSession(request, response);
      clause.userId = user?.id ?? null;
    }

    const memory = await Memory.get(clause);
    if (!memory)
      return response.status(404).json({ error: "Memory not found." });

    next();
  } catch (e) {
    console.error(e);
    return response.sendStatus(500);
  }
}

function memoryEndpoints(app) {
  if (!app) return;

  app.get(
    "/workspaces/:slug/memories",
    [
      validatedRequest,
      flexUserRoleValid([ROLES.all]),
      memoryFeatureEnabled,
      validWorkspaceSlug,

View on GitHub (pinned to 3aec848f28)

Solutions

  1. Re-fetch the memory list (GET /memories / workspace memories) and use an id from the fresh response
  2. Confirm you are authenticated as the owning user in multi-user mode
  3. Treat 404 as 'gone or not yours' — do not blindly retry
  4. If every id 404s at once, suspect DB connectivity: Memory.get masks errors as null, so check server logs

Example fix

// before
await fetch(`/memories/${memoryId}`, { method: 'PUT', ... });
// after
const fresh = (await (await fetch('/memories')).json()).memories ?? [];
if (!fresh.some((m) => m.id === Number(memoryId))) { refreshUI(); return; }
await fetch(`/memories/${memoryId}`, { method: 'PUT', ... });
Defensive patterns

Strategy: validation

Validate before calling

// Only mutate ids present in the freshest list the caller can see
const fresh = await (await fetch('/memories')).json();
const mine = new Set((fresh.memories ?? []).map((m) => m.id));
if (!mine.has(Number(memoryId))) throw new Error('Memory is gone or not owned by this user');

Type guard

function isOwnedMemoryId(list, id) {
  return typeof id === 'number' && Number.isInteger(id)
    && list.some((m) => m.id === id);
}

Prevention

When it happens

Trigger: Any /memories/:memoryId route where the id does not exist, was deleted, belongs to a different user (multi-user mode), is non-numeric, or the Prisma query errored (Memory.get's catch returns null).

Common situations: Stale UI after the memory was deleted from another tab/device; reusing an id captured under a different account; session switched mid-flow; DB outage masquerading as 404.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/f0bd783042ab10d0. Report an issue: GitHub.