Error & Event Codes¶
The PostgreSQL Permissions Model uses structured numeric codes for both informational events and errors. All codes are stored in the const.event_code table and organized into categories via const.event_category. Message templates in const.event_message provide human-readable descriptions with placeholder substitution.
Code ranges:
| Range | Type | Description |
|---|---|---|
| 10000 -- 29999 | Informational events | Logged to public.journal and auth.user_event |
| 30000 -- 39999 | Errors | Raised as PostgreSQL exceptions with ERRCODE |
| 50000+ | Reserved | Available for application-specific codes |
Placeholder syntax: Message templates use {placeholder} tokens that are filled from data_payload at display time. Common placeholders include {actor} (who performed the action), {username}, {email}, {tenant_title}, {group_title}, {permission_code}, and {perm_set_code}.
Event Codes¶
Events are logged to the public.journal and auth.user_event tables. They are organized by category and recorded whenever a state-changing operation occurs in the system.
User Events (user_event, 10001 -- 10999)¶
User lifecycle, authentication, identity management, and blacklist operations.
| Code | Name | Message Template |
|---|---|---|
| 10001 | user_created |
User "{username}" was created by {actor} |
| 10002 | user_updated |
User "{username}" was updated by {actor} |
| 10003 | user_deleted |
User "{username}" was deleted by {actor} |
| 10004 | user_enabled |
User "{username}" was enabled by {actor} |
| 10005 | user_disabled |
User "{username}" was disabled by {actor} |
| 10006 | user_locked |
User "{username}" was locked by {actor} |
| 10007 | user_unlocked |
User "{username}" was unlocked by {actor} |
| 10008 | user_registered |
User "{username}" registered via {provider} |
| 10010 | user_logged_in |
User "{username}" logged in |
| 10011 | user_logged_out |
User "{username}" logged out |
| 10012 | user_login_failed |
Login failed for "{username}": {reason} |
| 10020 | password_changed |
Password was changed for user "{username}" by {actor} |
| 10021 | password_reset_requested |
Password reset was requested for user "{username}" |
| 10022 | password_reset_completed |
Password reset was completed for user "{username}" |
| 10030 | identity_created |
Identity "{provider_code}" was created for user "{username}" by {actor} |
| 10031 | identity_updated |
Identity "{provider_code}" was updated for user "{username}" by {actor} |
| 10032 | identity_deleted |
Identity "{provider_code}" was deleted for user "{username}" by {actor} |
| 10033 | identity_enabled |
Identity "{provider_code}" was enabled for user "{username}" by {actor} |
| 10034 | identity_disabled |
Identity "{provider_code}" was disabled for user "{username}" by {actor} |
| 10040 | email_verified |
Email was verified for user "{username}" |
| 10041 | phone_verified |
Phone was verified for user "{username}" |
| 10050 | mfa_enabled |
MFA was enabled for user "{username}" by {actor} |
| 10051 | mfa_disabled |
MFA was disabled for user "{username}" by {actor} |
| 10070 | external_data_updated |
User "{username}" data was updated from external source |
| 10080 | user_blacklisted |
User "{username}" was added to blacklist by {actor}: {reason} |
| 10081 | user_unblacklisted |
User "{username}" was removed from blacklist by {actor} |
| 10082 | user_creation_blocked |
User creation was blocked by blacklist: {username} {provider_code} {provider_uid} |
| 10083 | user_auto_locked |
User account was auto-locked after too many failed login attempts |
| 10090 | mfa_enrolled |
MFA enrollment was initiated |
| 10091 | mfa_enrollment_confirmed |
MFA enrollment was confirmed with a valid code |
| 10092 | mfa_challenge_created |
MFA challenge token was created |
| 10093 | mfa_challenge_passed |
MFA challenge was successfully verified |
| 10094 | mfa_recovery_used |
MFA recovery code was used to pass challenge |
| 10095 | mfa_policy_created |
MFA policy rule was created |
| 10096 | mfa_policy_deleted |
MFA policy rule was deleted |
| 10097 | mfa_recovery_reset |
MFA recovery codes were regenerated |
Tenant Events (tenant_event, 11001 -- 11999)¶
Tenant creation, updates, deletion, and user access changes.
| Code | Name | Message Template |
|---|---|---|
| 11001 | tenant_created |
Tenant "{tenant_title}" was created by {actor} |
| 11002 | tenant_updated |
Tenant "{tenant_title}" was updated by {actor} |
| 11003 | tenant_deleted |
Tenant "{tenant_title}" was deleted by {actor} |
| 11010 | tenant_user_added |
User "{username}" was added to tenant "{tenant_title}" by {actor} |
| 11011 | tenant_user_removed |
User "{username}" was removed from tenant "{tenant_title}" by {actor} |
Permission Events (permission_event, 12001 -- 12999)¶
Permission CRUD, permission set lifecycle, and assignment/revocation operations.
| Code | Name | Message Template |
|---|---|---|
| 12001 | permission_created |
Permission "{permission_code}" was created by {actor} |
| 12002 | permission_updated |
Permission "{permission_code}" was updated by {actor} |
| 12003 | permission_deleted |
Permission "{permission_code}" was deleted by {actor} |
| 12010 | permission_assigned |
Permission "{permission_code}" was assigned to {target_type} "{target_name}" by {actor} |
| 12011 | permission_revoked |
Permission "{permission_code}" was revoked from {target_type} "{target_name}" by {actor} |
| 12020 | perm_set_created |
Permission set "{perm_set_code}" was created in tenant "{tenant_title}" by {actor} |
| 12021 | perm_set_updated |
Permission set "{perm_set_code}" was updated by {actor} |
| 12022 | perm_set_deleted |
Permission set "{perm_set_code}" was deleted by {actor} |
| 12023 | perm_set_assigned |
Permission set "{perm_set_code}" was assigned to {target_type} "{target_name}" by {actor} |
| 12024 | perm_set_revoked |
Permission set "{perm_set_code}" was revoked from {target_type} "{target_name}" by {actor} |
Group Events (group_event, 13001 -- 13999)¶
Group lifecycle, membership changes, external mapping management, and synchronization.
| Code | Name | Message Template |
|---|---|---|
| 13001 | group_created |
Group "{group_title}" was created in tenant "{tenant_title}" by {actor} |
| 13002 | group_updated |
Group "{group_title}" was updated by {actor} |
| 13003 | group_deleted |
Group "{group_title}" was deleted by {actor} |
| 13010 | group_member_added |
User "{username}" was added to group "{group_title}" by {actor} |
| 13011 | group_member_removed |
User "{username}" was removed from group "{group_title}" by {actor} |
| 13020 | group_mapping_created |
Mapping "{mapping_name}" was created for group "{group_title}" by {actor} |
| 13021 | group_mapping_deleted |
Mapping "{mapping_name}" was deleted from group "{group_title}" by {actor} |
| 13030 | group_members_synced |
Group members synchronized: {members_created} created, {members_deleted} deleted for group via mapping {user_group_mapping_id} |
API Key Events (apikey_event, 14001 -- 14999)¶
API key creation, updates, deletion, and validation results.
| Code | Name | Message Template |
|---|---|---|
| 14001 | apikey_created |
API key "{api_key_title}" was created by {actor} |
| 14002 | apikey_updated |
API key "{api_key_title}" was updated by {actor} |
| 14003 | apikey_deleted |
API key "{api_key_title}" was deleted by {actor} |
| 14010 | apikey_validated |
API key "{api_key_title}" was validated |
| 14011 | apikey_validation_failed |
API key validation failed: {reason} |
Token Events (token_event, 15001 -- 15999)¶
Token creation, usage, expiration, and validation failures.
| Code | Name | Message Template |
|---|---|---|
| 15001 | token_created |
Token was created for user "{username}" |
| 15002 | token_used |
Token was used by user "{username}" |
| 15003 | token_expired |
Token expired for user "{username}" |
| 15004 | token_failed |
Token validation failed for user "{username}": {reason} |
Provider Events (provider_event, 16001 -- 16999)¶
Identity provider lifecycle management.
| Code | Name | Message Template |
|---|---|---|
| 16001 | provider_created |
Provider "{provider_code}" was created by {actor} |
| 16002 | provider_updated |
Provider "{provider_code}" was updated by {actor} |
| 16003 | provider_deleted |
Provider "{provider_code}" was deleted by {actor} |
| 16004 | provider_enabled |
Provider "{provider_code}" was enabled by {actor} |
| 16005 | provider_disabled |
Provider "{provider_code}" was disabled by {actor} |
Maintenance Events (maintenance_event, 17001 -- 17999)¶
System maintenance and data retention operations.
| Code | Name | Message Template |
|---|---|---|
| 17001 | audit_data_purged |
Audit data purged by {actor}: {journal_deleted} journal entries and {user_events_deleted} user events removed |
Resource Access Events (resource_event, 18001 -- 18999)¶
Resource type registration and access control (grant, revoke, deny) operations.
| Code | Name | Message Template |
|---|---|---|
| 18001 | resource_type_created |
Resource type "{resource_type}" was created by {actor} |
| 18002 | resource_type_updated |
Resource type "{resource_type}" was updated by {actor} |
| 18003 | resource_role_created |
Resource role "{role_code}" was created by {actor} |
| 18004 | resource_role_updated |
Resource role "{role_code}" was updated by {actor} |
| 18005 | resource_role_deleted |
Resource role "{role_code}" was deleted by {actor} |
| 18010 | resource_access_granted |
Access to {resource_type} "{resource_id}" was granted to {target_type} "{target_name}" by {actor} |
| 18011 | resource_access_revoked |
Access to {resource_type} "{resource_id}" was revoked from {target_type} "{target_name}" by {actor} |
| 18012 | resource_access_denied |
Deny rule on {resource_type} "{resource_id}" was set for user "{target_name}" by {actor} |
| 18013 | resource_access_bulk_revoked |
All access to {resource_type} "{resource_id}" was revoked by {actor} |
| 18020 | resource_role_assigned |
Role "{role_code}" on {resource_type} "{resource_id}" was assigned to {target_type} "{target_name}" by {actor} |
| 18021 | resource_role_revoked |
Role "{role_code}" on {resource_type} "{resource_id}" was revoked from {target_type} "{target_name}" by {actor} |
Token Config Events (token_config_event, 19001 -- 19999)¶
Token type configuration changes (creating, updating, or deleting custom token types).
| Code | Name | Message Template |
|---|---|---|
| 19001 | token_type_created |
Token type "{token_type_code}" was created by {actor} |
| 19002 | token_type_updated |
Token type "{token_type_code}" was updated by {actor} |
| 19003 | token_type_deleted |
Token type "{token_type_code}" was deleted by {actor} |
Language Events (language_event, 20001 -- 20999)¶
Language registry operations.
| Code | Name | Message Template |
|---|---|---|
| 20001 | language_created |
Language "{language_code}" ({language_value}) was created by {actor} |
| 20002 | language_updated |
Language "{language_code}" was updated by {actor} |
| 20003 | language_deleted |
Language "{language_code}" was deleted by {actor} |
Translation Events (translation_event, 21001 -- 21999)¶
Translation CRUD and cross-language copy operations.
| Code | Name | Message Template |
|---|---|---|
| 21001 | translation_created |
Translation for "{data_group}.{data_object_code}" in language "{language_code}" was created by {actor} |
| 21002 | translation_updated |
Translation (id: {translation_id}) was updated by {actor} |
| 21003 | translation_deleted |
Translation (id: {translation_id}) was deleted by {actor} |
| 21004 | translations_copied |
Translations were copied from "{from_language}" to "{to_language}" by {actor} |
Invitation Events (invitation_event, 22001 -- 22999)¶
Invitation lifecycle, action completion/failure, and template management.
| Code | Name | Message Template |
|---|---|---|
| 22001 | invitation_created |
Invitation was sent to "{target_email}" for tenant "{tenant_title}" by {actor} |
| 22002 | invitation_accepted |
Invitation to tenant "{tenant_title}" was accepted by "{target_email}" |
| 22003 | invitation_rejected |
Invitation to tenant "{tenant_title}" was rejected by "{target_email}" |
| 22004 | invitation_revoked |
Invitation to "{target_email}" was revoked by {actor} |
| 22005 | invitation_expired |
Invitation to "{target_email}" for tenant "{tenant_title}" expired |
| 22006 | invitation_action_completed |
Invitation action "{action_type}" completed for "{target_email}" |
| 22007 | invitation_action_failed |
Invitation action "{action_type}" failed for "{target_email}": {error_message} |
| 22008 | invitation_completed |
All actions completed for invitation to "{target_email}" |
| 22009 | invitation_failed |
Invitation to "{target_email}" failed: required action "{action_type}" failed |
| 22010 | invitation_template_created |
Invitation template "{template_code}" was created by {actor} |
| 22011 | invitation_template_updated |
Invitation template "{template_code}" was updated by {actor} |
| 22012 | invitation_template_deleted |
Invitation template "{template_code}" was deleted by {actor} |
Error Codes¶
Errors are raised as PostgreSQL exceptions using the ERRCODE mechanism. Each error has a dedicated function in the error schema (e.g., error.raise_32001) that formats the exception message with contextual parameters and sets the appropriate error code. Application code can catch these errors using EXCEPTION WHEN SQLSTATE 'XXXXX' blocks.
Security Errors (security_error, 30001 -- 30999)¶
Authentication and token validation failures.
| Code | Function | Description |
|---|---|---|
| 30001 | error.raise_30001 |
API key/secret combination is not valid or API user has not been found |
| 30002 | error.raise_30002 |
Token is not valid or has expired |
| 30003 | error.raise_30003 |
Token was created for a different user |
| 30004 | error.raise_30004 |
Token has already been used |
| 30005 | error.raise_30005 |
Token does not exist |
Validation Errors (validation_error, 31001 -- 31999)¶
Missing or invalid required parameters in function calls.
| Code | Function | Description |
|---|---|---|
| 31001 | error.raise_31001 |
Either user group ID or target user ID must not be null |
| 31002 | error.raise_31002 |
Either permission set code or permission code must not be null |
| 31003 | error.raise_31003 |
Either permission ID or code must not be null |
| 31004 | error.raise_31004 |
Either mapped object ID or mapped role must not be empty |
| 31010 | error.raise_31010 |
Cannot modify or delete a system event code |
| 31011 | error.raise_31011 |
Event code does not exist |
| 31012 | error.raise_31012 |
Event category still has event codes and cannot be deleted |
| 31013 | error.raise_31013 |
Event ID is outside the allowed range for the category |
| 31014 | error.raise_31014 |
Event category does not exist |
Permission Errors (permission_error, 32001 -- 32999)¶
Permission and permission set lookup and assignment failures.
| Code | Function | Description |
|---|---|---|
| 32001 | error.raise_32001 |
User does not have the required permission |
| 32002 | error.raise_32002 |
Permission does not exist |
| 32003 | error.raise_32003 |
Permission is not assignable |
| 32004 | error.raise_32004 |
Permission set does not exist |
| 32005 | error.raise_32005 |
Permission set is not assignable |
| 32006 | error.raise_32006 |
Permission set is not defined in the specified tenant |
| 32007 | error.raise_32007 |
Parent permission does not exist |
| 32008 | error.raise_32008 |
Some permissions are not assignable |
User/Group Errors (user_error, 33001 -- 33999)¶
User, identity, group, provider, and ownership validation failures.
| Code | Function | Description |
|---|---|---|
| 33001 | error.raise_33001 |
User does not exist |
| 33002 | error.raise_33002 |
User is a system user (cannot be modified) |
| 33003 | error.raise_33003 |
User is not in active state |
| 33004 | error.raise_33004 |
User is locked out |
| 33005 | error.raise_33005 |
User is not supposed to log in |
| 33006 | error.raise_33006 |
User cannot be ensured for email provider (use registration instead) |
| 33007 | error.raise_33007 |
User identity is already in use |
| 33008 | error.raise_33008 |
User identity is not in active state |
| 33009 | error.raise_33009 |
User identity does not exist |
| 33010 | error.raise_33010 |
Provider is not in active state |
| 33011 | error.raise_33011 |
User group does not exist |
| 33012 | error.raise_33012 |
User group is not active |
| 33013 | error.raise_33013 |
User group is not assignable or is external |
| 33014 | error.raise_33014 |
User group is a system group |
| 33015 | error.raise_33015 |
User is not tenant or group owner |
| 33016 | error.raise_33016 |
Provider does not allow group mapping |
| 33017 | error.raise_33017 |
Provider does not allow group sync |
| 33018 | error.raise_33018 |
User is blacklisted and cannot be created |
| 33019 | error.raise_33019 |
User identity is blacklisted and cannot be created |
| 33020 | error.raise_33020 |
User could not be resolved by identifier |
| 33021 | error.raise_33021 |
User group could not be resolved by identifier |
Tenant Errors (tenant_error, 34001 -- 34999)¶
Tenant access validation.
| Code | Function | Description |
|---|---|---|
| 34001 | error.raise_34001 |
User has no access to this tenant |
| 34003 | error.raise_34003 |
Tenant could not be resolved by identifier |
Resource Access Errors (resource_error, 35001 -- 35999)¶
Resource-level ACL validation failures.
| Code | Function | Description |
|---|---|---|
| 35001 | error.raise_35001 |
User has no access to the specified resource |
| 35002 | error.raise_35002 |
Either target user ID or user group ID must be provided |
| 35003 | error.raise_35003 |
Resource type does not exist or is not active |
| 35004 | error.raise_35004 |
Access flag does not exist |
| 35005 | -- | Resource ID is missing a required key for the resource type's key_schema |
| 35006 | -- | Access flag is not valid for resource type |
| 35007 | error.raise_35007 |
Resource role does not exist or is not active |
| 35008 | error.raise_35008 |
Resource role cannot include flag -- not valid for resource type |
| 35009 | error.raise_35009 |
Resource role type mismatch at assignment |
Token Config Errors (token_config_error, 36001 -- 36999)¶
Token type configuration validation.
| Code | Function | Description |
|---|---|---|
| 36001 | error.raise_36001 |
Token type does not exist |
| 36002 | error.raise_36002 |
Token type is a system type and cannot be modified or deleted |
Language/Translation Errors (language_error, 37001 -- 37999)¶
Language and translation lookup failures.
| Code | Function | Description |
|---|---|---|
| 37001 | error.raise_37001 |
Language does not exist |
| 37002 | error.raise_37002 |
Translation does not exist |
MFA Errors (mfa_error, 38001 -- 38999)¶
Multi-factor authentication validation failures.
| Code | Function | Description |
|---|---|---|
| 38001 | error.raise_38001 |
MFA is already enrolled and confirmed for this type |
| 38002 | error.raise_38002 |
MFA is not enrolled for this type |
| 38003 | error.raise_38003 |
MFA enrollment is not confirmed |
| 38004 | error.raise_38004 |
The provided MFA code is not valid |
| 38005 | error.raise_38005 |
MFA verification is required |
| 38006 | error.raise_38006 |
MFA type does not exist or is inactive |
| 38007 | error.raise_38007 |
MFA policy does not exist |
Invitation Errors (invitation_error, 39001 -- 39999)¶
Invitation lifecycle and action validation failures.
| Code | Function | Description |
|---|---|---|
| 39001 | error.raise_39001 |
Invitation does not exist |
| 39002 | error.raise_39002 |
Invitation is not in pending state |
| 39003 | error.raise_39003 |
Invitation has expired |
| 39004 | error.raise_39004 |
Invitation action does not exist |
| 39005 | error.raise_39005 |
Invitation action is not in pending or processing state |
| 39006 | error.raise_39006 |
Invitation template does not exist or is inactive |
Legacy Code Mapping¶
The v1 system used error codes in the 52xxx range. For backwards compatibility, alias functions are provided that delegate to the current error functions. These aliases are defined in 016_functions_error.sql.
| Legacy Code | Current Code | Description |
|---|---|---|
| 52101 | 33006 | User cannot be ensured for email provider |
| 52102 | 33007 | User identity already in use |
| 52103 | 33001 | User not found |
| 52104 | 33002 | User is system |
| 52105 | 33003 | User not active |
| 52106 | 33004 | User locked |
| 52107 | 33010 | Provider not active |
| 52108 | 34001 | No tenant access |
| 52109 | 32001 | No permission |
| 52110 | 33008 | Identity not active |
| 52111 | 33009 | Identity not found |
| 52112 | 33005 | User cannot login |
| 52113 | 33016 | Provider does not allow group mapping |
| 52114 | 33017 | Provider does not allow group sync |
| 52115 | 33018 | User blacklisted |
| 52116 | 33019 | Identity blacklisted |
| 52171 | 33011 | Group not found |
| 52172 | 33012 | Group not active |
| 52173 | 33013 | Group not assignable |
| 52174 | 31004 | Either mapping ID or role required |
| 52175 | 32005 | Permission set not assignable |
| 52176 | 32003 | Permission not assignable |
| 52177 | 32006 | Permission set wrong tenant |
| 52178 | 32008 | Some permissions not assignable |
| 52179 | 32007 | Parent permission not found |
| 52180 | 32002 | Permission not found |
| 52181 | 32003 | Permission not assignable |
| 52271 | 33014 | Group is system |
| 52272 | 31001 | Either group or user required |
| 52273 | 31002 | Either perm set or permission required |
| 52274 | 31003 | Either permission ID or code required |
| 52275 | 32002 | Permission not found |
| 52276 | 30004 | Token already used |
| 52277 | 30005 | Token not found |
| 52278 | 30002 | Token invalid or expired |
| 52279 | 30003 | Token belongs to different user |
| 52282 | 32004 | Permission set not found |
| 52283 | 32005 | Permission set not assignable |
| 52301 | 30001 | API key/secret invalid |
| 52401 | 33015 | Not owner |
Catching Errors in PL/pgSQL¶
Error codes can be caught using standard PostgreSQL exception handling with SQLSTATE:
do $$
begin
perform auth.has_permission(1, 1001, 'orders.cancel_order');
exception
when sqlstate '32001' then
raise notice 'User does not have permission';
when sqlstate '33001' then
raise notice 'User not found';
end;
$$;
Custom Event Codes¶
Applications can register their own event categories and codes in the 50000+ range using the event code management functions. System-defined codes (those with is_system = true) cannot be modified or deleted.
-- Create a custom event category
select public.create_event_category(
_user_id := 1,
_category_code := 'order_event',
_title := 'Order Events',
_range_start := 50001,
_range_end := 50999,
_is_error := false
);
-- Create a custom event code within the category
select public.create_event_code(
_user_id := 1,
_event_id := 50001,
_code := 'order_placed',
_category_code := 'order_event',
_title := 'Order Placed',
_description := 'A new order was placed'
);