bitwarden/server · error · BadRequestException
InstallationId does not match current context.
Error message
InstallationId does not match current context.
What it means
Thrown by PushController.SendAsync (POST /push/send) when the request body carries an InstallationId that does not equal the InstallationId established in the authenticated current context. The push relay must target the installation the caller is authenticated as, so a mismatch is rejected as a 400.
Source
Thrown at src/Api/Platform/Push/Controllers/PushController.cs:94
CheckUsage();
await _pushRegistrationService.DeleteUserRegistrationOrganizationAsync(
model.Devices.Select(d => Prefix(d.Id)),
Prefix(model.OrganizationId));
}
[HttpPost("send")]
public async Task SendAsync([FromBody] PushSendRequestModel<JsonElement> model)
{
CheckUsage();
NotificationTarget target;
Guid targetId;
if (model.InstallationId.HasValue)
{
if (_currentContext.InstallationId!.Value != model.InstallationId.Value)
{
throw new BadRequestException("InstallationId does not match current context.");
}
target = NotificationTarget.Installation;
targetId = _currentContext.InstallationId.Value;
}
else if (model.UserId.HasValue)
{
target = NotificationTarget.User;
targetId = model.UserId.Value;
}
else if (model.OrganizationId.HasValue)
{
target = NotificationTarget.Organization;
targetId = model.OrganizationId.Value;
}
else
{
throw new UnreachableException("Model validation should have prevented getting here.");View on GitHub (pinned to e93b962371)
Solutions
- Ensure the InstallationId in the request body matches the installation the caller authenticated as.
- Omit InstallationId from the body and target by UserId or OrganizationId instead if installation-level broadcast is not intended.
- Re-issue the installation token/credentials for the correct deployment and retry.
- Log both the context InstallationId and the body InstallationId to confirm which is wrong.
Example fix
// before: body carries a different installation id
{ "installationId": "<wrong-guid>", "type": 0, ... }
// after: match the authenticated installation, or target a user/org
{ "userId": "<user-guid>", "type": 0, ... } Defensive patterns
Strategy: validation
Validate before calling
// Do not send an installationId that differs from the authenticated context
if (body.installationId && body.installationId !== currentContext.installationId) {
throw new Error('Body installationId must match the authenticated installation');
} Type guard
function installationMatches(body: { installationId?: string }, ctx: { installationId?: string }): boolean {
return !body.installationId || body.installationId === ctx.installationId;
} Try / catch
try {
await api.pushSend(body);
} catch (e) {
if (e.status === 400 && /InstallationId does not match/i.test(e.message)) {
delete body.installationId; // fall back to user/org targeting
return api.pushSend(body);
}
throw e;
} Prevention
- Never hard-code an installationId in the request body; derive it from the auth context.
- Prefer user/org targeting over installation targeting when possible.
- Ensure the installation token matches the deployment you are calling.
When it happens
Trigger: POST /push/send with a JSON body whose InstallationId field is set to a value different from the installation the request was authenticated under (the installation claim in the auth token/context).
Common situations: Client mixed up installation credentials across deployments (e.g. sent a cloud installation id while authenticated as a different installation); a stale token from a previous installation; the body was templated with the wrong id.
Related errors
- Not correctly configured for push relays.
- You cannot remove yourself.
- Organization already belongs to a provider.
- The organization is subscribed to Secrets Manager. Please co
- Provider must be of type Reseller in order to assign Organiz
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/e5f6cd73ab43ddb7.
Report an issue: GitHub.