Mintplex-Labs/anything-llm · error

Device not found

Error message

Device not found

What it means

validDeviceToken resolves the header token with MobileDevice.get({ token }); if no desktop_mobile_devices row has that token it responds 400 { error: 'Device not found' }. On these routes devices are identified by their uuid v4 token (issued at /mobile/register and stored in the DB), not by id.

Source

Thrown at server/endpoints/mobile/middleware/index.js:23

/**
 * Validates the device id from the request headers by checking if the device
 * exists in the database and is approved.
 * @param {import("express").Request} request
 * @param {import("express").Response} response
 * @param {import("express").NextFunction} next
 */
async function validDeviceToken(request, response, next) {
  try {
    const token = request.header("x-anythingllm-mobile-device-token");
    if (!token)
      return response.status(400).json({ error: "Device token is required" });

    const device = await MobileDevice.get(
      { token: String(token) },
      { user: true }
    );
    if (!device)
      return response.status(400).json({ error: "Device not found" });
    if (!device.approved)
      return response.status(400).json({ error: "Device not approved" });

    // If the device is associated with a user then we can associate it with the locals
    // so we can reuse it later.
    if (device.user) {
      if (device.user.suspended)
        return response.status(400).json({ error: "User is suspended." });
      response.locals.user = device.user;
    }

    delete device.user;
    response.locals.device = device;
    next();
  } catch (error) {
    console.error("validDeviceToken", error);
    response.status(500).json({ error: "Invalid middleware response" });
  }

View on GitHub (pinned to 3aec848f28)

Solutions

  1. Re-register: admin generates fresh connect-info/QR, app POSTs /mobile/register, store the new token
  2. If the device should still exist, compare the stored token against the DB row (SELECT * FROM desktop_mobile_devices WHERE token = '...')
  3. After any DB reset, expect all previously issued device tokens to be dead

Example fix

// before
const res = await api.command('workspaces');
if (!res.ok) throw new Error(res.status);

// after
const res = await api.command('workspaces');
if (res.status === 400 && (await res.json()).error === 'Device not found') {
  await Storage.remove('deviceToken');
  return navigation.reset('PairScreen'); // re-register flow
}
Defensive patterns

Strategy: fallback

Try / catch

try {
  await api.command('workspaces');
} catch (e) {
  if (e.status === 400 && e.body?.error === 'Device not found') {
    await clearStoredToken();
    return startPairingFlow(); // fallback: re-register for a fresh token
  }
  throw e;
}

Prevention

When it happens

Trigger: Using a token whose device row the admin deleted (DELETE /api/mobile/:id); a token truncated or altered in storage/transit; pointing the app at a different backend instance or database that never registered the device.

Common situations: Device revoked by admin while the phone still caches the token; server DB reset or restore wiping desktop_mobile_devices; switching the app between local and hosted AnythingLLM instances.

Related errors


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