This reference guide documents all exception codes that may be returned by the acre Access Control API. Understanding these exceptions helps you build robust error handling into your integrations.
| Category | Description |
|---|---|
| Authentication Errors | Login, password, and user account issues |
| Permission Errors | Access control and authorization failures |
| Object Errors | CRUD operation failures |
| Validation Errors | Data format and constraint violations |
| Hardware Errors | Controller and peripheral issues |
| Instance Errors | Multi-tenant and instance management issues |
| Card Errors | Card assignment and credential issues |
| Query Errors | Search and aggregate operation failures |
Important: The acre API wrapper throws
FailedOutcomeExceptioninstead ofKeepException. The underlying REST API returns KeepException error codes, but the C# wrapper wraps these in FailedOutcomeException. Always handle null returns and check exception details.
using Flurl.Http;
using Feenics.Keep.WebApi.Wrapper;
public async Task<PersonInfo?> AddPersonSafelyAsync(InstanceInfo instance, PersonInfo newPerson)
{
try
{
// Wrapper returns the created person or throws on error
var person = await client.AddPersonAsync(instance, newPerson);
// Important: Some wrapper methods may return null instead of throwing
if (person == null)
{
Console.WriteLine("Person creation returned null - check permissions or instance state");
return null;
}
return person;
}
catch (FailedOutcomeException ex) when (ex.HttpStatus == System.Net.HttpStatusCode.Conflict)
{
// Duplicate name or similar conflict
// ResponseString contains the full KeepException details
Console.WriteLine($"Conflict creating person: {ex.ResponseString}");
return null;
}
catch (FailedOutcomeException ex) when (ex.HttpStatus == System.Net.HttpStatusCode.Forbidden)
{
// Permission denied - ResponseString provides specific permission error details
Console.WriteLine($"Permission denied: {ex.ResponseString}");
return null;
}
catch (FailedOutcomeException ex) when (ex.HttpStatus == System.Net.HttpStatusCode.BadRequest)
{
// Validation error - ResponseString includes which validation rule failed
Console.WriteLine($"Validation failed: {ex.ResponseString}");
return null;
}
catch (FailedOutcomeException ex)
{
// Other API errors (500, etc.) - always log ResponseString for troubleshooting
Console.WriteLine($"API error: HTTP {ex.HttpStatus} - {ex.ResponseString}");
return null;
}
catch (FlurlHttpException ex)
{
// Network-level errors (connection timeout, DNS failure, etc.)
Console.WriteLine($"Network error: {ex.Message}");
return null;
}
catch (Exception ex)
{
// Unexpected errors - log and rethrow
Console.WriteLine($"Unexpected error: {ex.Message}");
throw;
}
}
When calling the REST API directly (not using the C# wrapper), the API returns JSON error responses with KeepException details:
// Direct HTTP call - returns KeepException details in response body
using System.Net.Http;
using System.Text.Json;
var response = await httpClient.PostAsJsonAsync($"{apiUrl}/api/f/{instanceKey}/Person", newPerson);
if (!response.IsSuccessStatusCode)
{
var errorJson = await response.Content.ReadAsStringAsync();
var error = JsonDocument.Parse(errorJson);
// Access error details from JSON response
var exceptionCode = error.RootElement.GetProperty("Error").GetString();
var message = error.RootElement.GetProperty("Message").GetString();
switch (exceptionCode)
{
case "CannotInsertDuplicateName":
Console.WriteLine($"A person with this name already exists: {message}");
break;
case "PermissionsError":
Console.WriteLine($"Permission denied: {message}");
break;
default:
Console.WriteLine($"Error: {exceptionCode} - {message}");
break;
}
}
import requests
response = requests.post(f"{api_url}/api/f/{instance_key}/Person",
json=person_data, headers=headers)
if response.status_code != 200:
error = response.json()
error_code = error.get('Error', 'Unknown')
if error_code == 'CannotInsertDuplicateName':
print(f"Duplicate name: {person_data['CommonName']}")
elif error_code == 'PermissionsError':
print("Permission denied")
else:
print(f"Error: {error_code} - {error.get('Message')}")
Issues related to user login, passwords, and account status.
| Code | Description | Resolution |
|---|---|---|
UserDoesNotExist |
The specified username was not found | Verify username spelling and case |
IncorrectPassword |
The password provided is wrong | Verify password; check for caps lock |
NewPasswordRequired |
User must set a new password before continuing | Prompt user for password change |
UserIsDisabled |
The user account has been disabled | Contact system administrator |
UserIsLockedOut |
Account locked due to failed login attempts | Wait for lockout period or contact admin |
PasswordExpired |
The password has exceeded its age limit | User must change password |
UserCannotChangePassword |
Policy prevents this user from changing password | Contact system administrator |
CannnotChangePasswordOnLogin |
Password change not allowed during login | Use separate password change flow |
PasswordDoesNotMeetMinimumLength |
New password is too short | Use a longer password |
PasswordDoesNotMeetComplexityRule |
New password doesn’t meet complexity requirements | Include uppercase, lowercase, numbers, symbols |
PasswordRecentlyUsed |
New password was used previously | Choose a different password |
MustSupplyTwoFactorPassword |
Two-factor authentication required | Provide 2FA code |
IncorrectTwoFactorPassword |
The 2FA code is incorrect | Verify 2FA code; may need new code |
CurrentUserNotSet |
No authenticated user context | Ensure proper authentication |
Authorization and access control failures.
| Code | Description | Resolution |
|---|---|---|
PermissionsError |
Generic permission denied | Check user’s Operation Rights |
UnableToMoveToFolderMissingPermissions |
Cannot move object to target folder | Grant folder permissions or choose different folder |
UnableToTakeOwnershipMissingPermissions |
Cannot take ownership of object | Grant ownership permissions |
UnableToSearchHiddenObjectsMissingPermissions |
Cannot search hidden objects | Grant hidden object search permission |
MissingSystemInPermissionsTest |
Permission check missing system context | Verify permission configuration |
Failures during create, read, update, or delete operations.
| Code | Description | Resolution |
|---|---|---|
ObjectNotFound |
The requested object doesn’t exist | Verify object Key; may have been deleted |
UnableToUpdateObject |
Update operation failed | Check object state and permissions |
CannotUpdateMissingObjectId |
Object ID not provided for update | Include object ID/Key in update request |
MissingFolder |
The specified folder doesn’t exist | Create folder or use existing one |
IncorrectUsageKeyProvidedOnInsert |
Wrong key format used during creation | Use correct key format for object type |
CannotInsertDuplicateName |
Object with same name exists | Use unique name or update existing object |
CannotInsertDuplicateUser |
Username already exists | Choose different username |
GroupDoesNotExist |
The specified group was not found | Verify group Key |
ArgumentNotAnObjectId |
Invalid object ID format | Use valid MongoDB ObjectId format |
ValueCannotBeNull |
Required field is null | Provide required field value |
UsernameCannotBeNull |
Username field is required | Provide username |
CannotChangeFolder |
Object cannot be moved to different folder | Folder assignment is fixed for this object type |
CannotRemoveMultipleLinkedObjects |
Cannot bulk remove linked objects | Remove links individually |
NotModified |
Update contained no changes | Object is already in desired state |
Data format and constraint violations.
| Code | Description | Resolution |
|---|---|---|
ValidationError |
Generic validation failure | Check error message for specific field |
BadQueryFormat |
MongoDB query syntax error | Verify query JSON format |
InvalidOperation |
Operation not valid in current context | Check object state before operation |
InvalidAggregateOperation |
Aggregate pipeline error | Verify aggregate stage syntax |
InvalidAggregateTimeout |
Aggregate operation timed out | Simplify query or use streaming |
QueryTooLarge |
Query results exceed maximum size | Use pagination or streaming |
Controller, downstream, and peripheral device issues.
| Code | Description | Resolution |
|---|---|---|
MaxDownstreamExceeded |
Controller downstream limit reached | Use different controller or remove unused downstreams |
MaxDownstreamPeripheralsExceeded |
Downstream peripheral limit reached | Balance peripherals across downstreams |
MaxPeripheralsExceeded |
Maximum peripherals exceeded | Redistribute across controllers |
PeripheralMissingDownstreamLink |
Peripheral not linked to downstream | Add ObjectLink to downstream |
MissingControllerLink |
Object missing controller reference | Link object to controller |
CannotUpdateControllerPackage |
Controller firmware update failed | Check controller connectivity |
CannotSetDestinationDispatchSettings |
Invalid dispatch configuration | Verify dispatch settings format |
CannotSetDestinationReaderSettings |
Invalid reader settings | Verify reader configuration |
CannotChangeControllerType |
Controller type cannot be changed | Create new controller of desired type |
CannotChangeControllerToSameType |
Already the specified type | No action needed |
CannotChangeControllerNoCompatibleType |
No compatible conversion available | Create new controller instead |
IncorrectAddressingModeForInterface |
Interface addressing mode mismatch | Configure correct addressing mode |
InputScannerReportingPrioritiesIncorrect |
Invalid input scanner configuration | Fix reporting priorities |
ServiceContainerNotFoundByMacAddress |
Controller not found by MAC | Verify MAC address; check controller registration |
ServiceContainerHasAssociatedUser |
Controller already has user association | Remove existing user association first |
ServiceContainerNonceIsNull |
Controller security nonce missing | Re-register controller |
DuplicateServiceContainerNonce |
Duplicate controller security token | Re-register controller with new nonce |
DuplicateMacAddress |
MAC address already registered | Verify MAC address uniqueness |
MustDisableIfMissingMacAddress |
Controller without MAC must be disabled | Add MAC address or disable controller |
ReaderIsNotVersioned |
Reader doesn’t support versioning | Use compatible reader |
ReaderIsNotSchlage |
Operation requires Schlage reader | Use Schlage reader |
DuplicateEngageDevice |
Engage device already registered | Verify device ID uniqueness |
DuplicateElevatorUserSettingForController |
Duplicate elevator configuration | Remove duplicate settings |
Multi-tenant and instance management issues.
| Code | Description | Resolution |
|---|---|---|
InstanceDoesNotExist |
The specified instance was not found | Verify instance Key; check permissions |
MissingInstance |
No instance context provided | Include instance in request |
MissingInInstanceLink |
Object missing instance link | Add ObjectLink to instance |
MissingInstanceScopeLink |
Object missing instance scope | Set instance scope |
MissingCurrentInstance |
No current instance set | Call GetCurrentInstance first |
CurrentInstanceNotRoot |
Operation requires root instance | Switch to root instance |
UnableToScopeObjectToInstance |
Cannot scope object to instance | Check instance hierarchy and permissions |
CannotMoveInstanceToItself |
Cannot move instance to itself | Select different target instance |
CannotMoveInstanceToNonVarInstance |
Target must be VAR instance | Move to VAR instance only |
CannotMoveSharedInstance |
Shared instances cannot be moved | Convert from shared first |
CannotMoveInstanceAlreadyInTargetInstance |
Already in target instance | No action needed |
CannotMoveEnterpriseToEnterprise |
Cannot move enterprise to enterprise | Use different target type |
CannotObliterateRootInstance |
Cannot delete root instance | Cannot perform this operation |
DuplicateInstanceName |
Instance name already exists | Use unique instance name |
InvalidInstanceName |
Instance name is invalid | Use valid characters in name |
NotVarInstance |
Operation requires VAR instance | Switch to VAR instance |
InstanceIsDisabled |
Instance has been disabled | Enable instance or contact admin |
Card assignment and credential management issues.
| Code | Description | Resolution |
|---|---|---|
CardIsAlreadyAssigned |
Card number already in use | Use different card number or unassign existing |
DuplicateCardNumberInBatch |
Same card number appears twice in batch | Remove duplicate from batch |
DuplicateCardNumberInPerson |
Person already has this card | Card already assigned to this person |
CannotChangeEncodedCardNumber |
Encoded card number is immutable | Create new card assignment |
CannotChangeCardHexValue |
Card hex value cannot be modified | Create new card assignment |
CardHexValueNotPadded |
Card hex value needs padding | Pad hex value to correct length |
CardHexValueNotValid |
Invalid card hex format | Use valid hexadecimal format |
CannotDeleteCardAssignment |
Card assignment cannot be deleted | Check card status and linked events |
DuplicatePinCode |
PIN code already in use | Use different PIN code |
MissingPersonForUser |
User has no linked person record | Link user to person record |
MultipleUsersForPerson |
Person has multiple user accounts | Remove duplicate user accounts |
Search and aggregate operation failures.
| Code | Description | Resolution |
|---|---|---|
BadQueryFormat |
MongoDB query has syntax errors | Validate JSON query syntax |
QueryTooLarge |
Query results exceed size limits | Use pagination, streaming, or narrower criteria |
InvalidAggregateOperation |
Aggregate pipeline stage is invalid | Check aggregate stage syntax |
InvalidAggregateTimeout |
Aggregate operation exceeded timeout | Simplify pipeline or use background processing |
General system and infrastructure issues.
| Code | Description | Resolution |
|---|---|---|
MongoInitializationFailure |
Database initialization failed | Contact support; check database connectivity |
UnexpectedGeneralException |
Unexpected error occurred | Check logs; contact support if persistent |
UnableToFindAndUpdateIdentityCounter |
ID generation failed | Contact support |
CannotChangeRecordId |
Record ID cannot be modified | IDs are immutable |
UnableToAquireLock |
Could not acquire database lock | Retry operation; check for deadlocks |
NoMessage |
Error occurred without message | Check logs for additional details |
CannotRemoveConfiguration |
Configuration cannot be removed | Check dependencies |
Holiday management and subscription issues.
| Code | Description | Resolution |
|---|---|---|
ExceedingMaximumHolidayDayLimit |
Too many holiday days configured | Remove unused holidays |
ExceedingMaximumHolidayTypesLimit |
Too many holiday types | Consolidate holiday types |
AlreadyUsingHoliday2 |
Holiday2 already in use | Use different holiday slot |
ExceedingMaximumHolidayForDaysValue |
Holiday duration too long | Shorten holiday span |
MasterHolidayOptInNotSet |
Master holiday opt-in required | Enable master holiday subscription |
HolidayDayAlreadySubscribed |
Already subscribed to this holiday | No action needed |
NotMasterHoliday |
Operation requires master holiday | Use master holiday |
CannotEditSubscribedHolidayDay |
Subscribed holidays are read-only | Edit master holiday instead |
CannotSubscribeMasterHolidayDayToItself |
Cannot self-subscribe | Select different holiday |
Other specialized error conditions.
| Code | Description | Resolution |
|---|---|---|
CannotInsertDuplicateMoniker |
Moniker already exists | Use unique moniker |
DuplicateOrigoConfiguration |
Origo config already exists | Update existing or use unique name |