Mintplex-Labs/anything-llm · error

Device not approved

Error message

Device not approved

What it means

validDeviceToken found the device by token but its approved column is false. Devices created by POST /mobile/register are not auto-approved; an admin must POST /api/mobile/update/:id with { approved: true } (approved is the only writable field). Until then every device-authenticated call returns 400 { error: 'Device not approved' }.

Source

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

 * 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. Have an admin approve: POST /api/mobile/update/<device id> with body {"approved":true}
  2. In the mobile client, treat 'Device not approved' as a distinct 'waiting for approval' state and poll gently — do not re-register on this error
  3. If approval was wrongly revoked, set approved:true again via the same update endpoint

Example fix

// before — client retries instantly in a loop
while (true) await api.command('workspaces');

// after — recognize pending state and back off
const res = await api.command('workspaces');
if ((await res.json()).error === 'Device not approved') {
  setStatus('awaiting_admin_approval');
  await sleep(5000); // poll politely
}
Defensive patterns

Strategy: retry

Try / catch

try {
  await api.command('workspaces');
} catch (e) {
  if (e.status === 400 && e.body?.error === 'Device not approved') {
    scheduleApprovalPoll(5000); // retry with backoff until admin approves
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: The app registers, saves its token, and immediately calls further /api/mobile/* endpoints before an admin approves it; or the admin sets approved back to false to revoke live access while keeping the row.

Common situations: Race between registration and approval during demos/tests; approval step missed because the flow wasn't obvious; revoke-by-unapprove used instead of delete.

Related errors


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