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
- Set the header: 'x-anythingllm-mobile-device-token': '<token from /mobile/register>'
- Check exact spelling — dashes, full lowercase, whole name
- 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
- Centralize header injection in one API client wrapper so no call can forget it
- Persist the device token immediately after /mobile/register succeeds
- On CORS setups, verify the header survives preflight (Access-Control-Allow-Headers)
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
- Device not found
- Registration token is required
- Device not approved
- User is suspended.
- Public token is required to validate a temporary auth token.
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/b2eedcf265665d79.
Report an issue: GitHub.