appwrite/appwrite · error · Appwrite\Extend\Exception
user_id_missing
user_id_missing
Error message
When using account API key, make sure to pass x-appwrite-user header with your user ID.
What it means
Thrown in the account-API-key validator (app/init/resources/request.php:1048) when a decoded API key carries a userId but the x-appwrite-user header is missing or does not match. This binds the account key to the specific user it was issued for.
Source
Thrown at app/init/resources/request.php:1048
if (empty($key)) {
return null;
}
$key = Key::decode($project, $team, $user, $key);
$userHeader = $request->getHeaderLine('x-appwrite-user');
$organizationHeader = $request->getHeaderLine('x-appwrite-organization');
$projectHeader = $request->getHeaderLine('x-appwrite-project');
if (! empty($key->getProjectId())) {
if (empty($projectHeader) || $projectHeader !== $key->getProjectId()) {
throw new Exception(Exception::PROJECT_ID_MISSING);
}
}
if (! empty($key->getUserId())) {
if (empty($userHeader) || $userHeader !== $key->getUserId()) {
throw new Exception(Exception::USER_ID_MISSING);
}
}
if (! empty($key->getTeamId())) {
if (empty($organizationHeader) || $organizationHeader !== $key->getTeamId()) {
throw new Exception(Exception::ORGANIZATION_ID_MISSING);
}
}
return $key;
}, ['request', 'project', 'team', 'user']);
$context->set('resourceToken', function ($project, $dbForProject, $request, Authorization $authorization) {
$tokenJWT = $request->getParam('token');
if (! empty($tokenJWT) && ! $project->isEmpty()) { // JWT authentication
// Use a large but reasonable maxAge to avoid auto-exp when token has no expiry
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), RESOURCE_TOKEN_ALGORITHM, RESOURCE_TOKEN_MAX_AGE, RESOURCE_TOKEN_LEEWAY); // Instantiate with key, algo, maxAge and leeway.View on GitHub (pinned to cd368e707d)
Solutions
- Set x-appwrite-user (client.setHeader or SDK equivalent) to the key's userId.
- Confirm the userId in the key matches the user the client means to act as.
- Ensure proxies do not strip x-appwrite-user.
- If using the SDK, configure it to send both the key and the user header together.
Example fix
// before
client.setHeader('x-appwrite-key', accountApiKey);
// after
client.setHeader('x-appwrite-key', accountApiKey);
client.setHeader('x-appwrite-user', userId); Defensive patterns
Strategy: validation
Validate before calling
// Ensure x-appwrite-user is set whenever an account API key is used
function ensureUserHeader(headers, keyUserId) {
if (keyUserId && headers['x-appwrite-user'] !== keyUserId) {
headers['x-appwrite-user'] = keyUserId;
}
return headers;
} Prevention
- When using an account API key, always set x-appwrite-user to the key's userId.
- Ensure proxies forward x-appwrite-user.
- Keep the key and the user header paired in SDK configuration.
When it happens
Trigger: Client authenticates with an account API key whose payload includes a userId, but x-appwrite-user is absent or mismatched. The check at line ~1046 compares $userHeader !== $key->getUserId().
Common situations: SDK not configured to send x-appwrite-user when using an account API key; header stripped by proxy; key for user A used with a client pointing at user B; SSR setup missing the user header.
Related errors
- project_id_missing
- organization_id_missing
- user_api_key_and_session_set
- account_key_expired
- user_api_key_and_session_set
AI-assisted analysis of appwrite/appwrite@cd368e707d (2026-08-12).
Data as JSON: /api/errors/ca5e9dd3c4df69cf.
Report an issue: GitHub.