Mintplex-Labs/anything-llm · error

Device token is required

Error message

Device token is required

What it means

validDeviceToken middleware guards device-authenticated /api/mobile routes. It reads the x-anythingllm-mobile-device-token header; when the header is absent or empty it responds 400 { error: 'Device token is required' } before any handler runs. This is the long-lived device token issued by POST /mobile/register, not the temporary registration token.

Source

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

const { MobileDevice } = require("../../../models/mobileDevice");
const { SystemSettings } = require("../../../models/systemSettings");
const { User } = require("../../../models/user");

/**
 * 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;
    }

View on GitHub (pinned to 3aec848f28)

Solutions

  1. Set the header: 'x-anythingllm-mobile-device-token': '<token from /mobile/register>'
  2. Check exact spelling — dashes, full lowercase, whole name
  3. If behind a proxy/gateway, confirm custom x- headers are forwarded and allowed in CORS config

Example fix

// before
fetch('/api/mobile/util', { method: 'POST', body: JSON.stringify(payload) });

// after
fetch('/api/mobile/util', {
  method: 'POST',
  headers: { 'x-anythingllm-mobile-device-token': deviceToken },
  body: JSON.stringify(payload),
});
Defensive patterns

Strategy: validation

Validate before calling

if (!deviceToken) throw new Error('Device not paired — run registration first');
const headers = { 'x-anythingllm-mobile-device-token': deviceToken };

Prevention

When it happens

Trigger: Calling a device-authenticated /api/mobile endpoint without the x-anythingllm-mobile-device-token header, sending it empty, misspelling it (e.g. underscores instead of dashes), or putting it in Authorization instead.

Common situations: Token not persisted after first registration; CORS preflight stripping custom x- headers because Access-Control-Allow-Headers omits it; reverse proxy (nginx) dropping custom headers by default.

Related errors


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