bitwarden/server · error · BadRequestException

Cipher was not unarchived. Ensure the provided ID is correct

Error message

Cipher was not unarchived. Ensure the provided ID is correct and you have permission to archive it.

What it means

PUT /ciphers/{id}/unarchive (PutUnarchive) delegates to UnarchiveManyAsync with a single id. If zero ciphers are unarchived — wrong id, not owned, no permission, or the cipher isn't archived — the server returns HTTP 400. (Note: the message text erroneously says 'archive it' rather than 'unarchive it', but the cause is the unarchive operation.)

Source

Thrown at src/Api/Vault/Controllers/CiphersController.cs:1092

            !await CanDeleteOrRestoreCipherAsAdminAsync(new Guid(model.OrganizationId), cipherIds))
        {
            throw new NotFoundException();
        }

        var userId = _userService.GetProperUserId(User).Value;
        await _cipherService.SoftDeleteManyAsync(cipherIds, userId, new Guid(model.OrganizationId), true);
    }

    [HttpPut("{id}/unarchive")]
    public async Task<CipherResponseModel> PutUnarchive(Guid id)
    {
        var userId = _userService.GetProperUserId(User).Value;

        var unarchivedCipherDetails = await _unarchiveCiphersCommand.UnarchiveManyAsync([id], userId);

        if (unarchivedCipherDetails.Count == 0)
        {
            throw new BadRequestException("Cipher was not unarchived. Ensure the provided ID is correct and you have permission to archive it.");
        }

        var unarchivedCipher = unarchivedCipherDetails.First();
        return new CipherResponseModel(unarchivedCipher,
            await _userService.GetUserByPrincipalAsync(User),
            await GetOrganizationAbilityAsync(unarchivedCipher),
            _globalSettings
        );
    }

    [HttpPut("unarchive")]
    public async Task<ListResponseModel<CipherResponseModel>> PutUnarchiveMany([FromBody] CipherBulkUnarchiveRequestModel model)
    {
        if (!_globalSettings.SelfHosted && model.Ids.Count() > 500)
        {
            throw new BadRequestException("You can only unarchive up to 500 items at a time.");
        }

View on GitHub (pinned to e93b962371)

Solutions

  1. Verify the cipher id is correct, owned/editable, and is actually in an archived state.
  2. Re-sync the vault to refresh cipher state before retrying.
  3. For org ciphers, confirm edit permission on the relevant collection.
Defensive patterns

Strategy: validation

Validate before calling

async function safeUnarchive(id) {
  const c = await api.get(`/ciphers/${id}`).catch(() => null);
  if (!c || !c.editable) throw new Error('Cipher missing or not editable; cannot unarchive');
  return api.put(`/ciphers/${id}/unarchive`);
}

Type guard

function isUnarchivable(cipher: { id?: string; editable?: boolean; deletedDate?: string | null } | null): boolean {
  return !!cipher && !!cipher.id && cipher.editable === true && !cipher.deletedDate;
}

Try / catch

try { await api.put(`/ciphers/${id}/unarchive`); }
catch (e) {
  if (e?.response?.status === 400 && /not unarchived/i.test(e.response.data?.message ?? '')) {
    await syncVault(); // verify state/permissions; note the server message erroneously says 'archive'
  } else throw e;
}

Prevention

When it happens

Trigger: PUT /ciphers/{id}/unarchive where the id does not exist, belongs to another user, lacks permission, or is not currently archived.

Common situations: Unarchiving a cipher that was permanently deleted by another client; unarchiving an org cipher without edit rights; a stale cipher id after sync.

Related errors


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