bitwarden/server · error · BadRequestException

A secret can only be in one project at a time.

Error message

A secret can only be in one project at a time.

What it means

Thrown at SecretsManagerPortingController.cs:75 inside Import. The payload contains at least one secret whose ProjectIds collection has more than one entry (importRequest.Secrets.Any(s => s.ProjectIds.Count() > 1)). Bitwarden Secrets Manager enforces a single-project-per-secret model, so the controller throws BadRequestException("A secret can only be in one project at a time.") -> HTTP 400.

Source

Thrown at src/Api/SecretsManager/Controllers/SecretsManagerPortingController.cs:75

        return new SMExportResponseModel(projects.Select(p => p.Project), secrets.Select(s => s.Secret));
    }

    [HttpPost("sm/{organizationId}/import")]
    public async Task Import([FromRoute] Guid organizationId, [FromBody] SMImportRequestModel importRequest)
    {
        if (!await _currentContext.OrganizationAdmin(organizationId) || !_currentContext.AccessSecretsManager(organizationId))
        {
            throw new NotFoundException();
        }

        if (importRequest.Projects?.Count() > 1000 || importRequest.Secrets?.Count() > 6000)
        {
            throw new BadRequestException("You cannot import this much data at once, the limit is 1000 projects and 6000 secrets.");
        }

        if (importRequest.Secrets.Any(s => s.ProjectIds.Count() > 1))
        {
            throw new BadRequestException("A secret can only be in one project at a time.");
        }

        var projectsToAdd = importRequest.Projects?.Count();
        if (projectsToAdd is > 0)
        {
            var (max, overMax) = await _maxProjectsQuery.GetByOrgIdAsync(organizationId, projectsToAdd.Value);
            if (overMax != null && overMax.Value)
            {
                throw new BadRequestException($"The maximum number of projects for this plan is ({max}).");
            }
        }

        await _importCommand.ImportAsync(organizationId, importRequest.ToSMImport());
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Reduce each secret to exactly one project id (pick the primary project) before importing.
  2. If a secret truly must appear in multiple projects, import duplicates under each project separately.
  3. Validate the payload with a pre-pass that asserts every secret has at most one project id.

Example fix

// before: secret mapped to many projects
var payload = new SMImportRequestModel {
    Secrets = srcSecrets.Select(s => new SMImportSecret { Key = s.Key, Value = s.Value, ProjectIds = s.Folders }) // >1
};

// after: one project per secret
var payload = new SMImportRequestModel {
    Secrets = srcSecrets.Select(s => new SMImportSecret { Key = s.Key, Value = s.Value, ProjectIds = new[] { s.PrimaryFolder } })
};
Defensive patterns

Strategy: validation

Validate before calling

var bad = import.Secrets.Where(s => s.ProjectIds.Count() > 1).ToList();
if (bad.Any()) throw new ArgumentException($"{bad.Count} secret(s) reference multiple projects");

Prevention

When it happens

Trigger: POST /sm/{org}/import where any imported secret references multiple project ids, e.g. data exported from a system that allowed many-to-many secret/project relationships.

Common situations: Migrating from a tool where a secret could belong to several folders/projects; mapping error during payload conversion; duplicated project id on a single secret.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/09667c945be3ab9c. Report an issue: GitHub.