Skip to content

Error handling

Every error ADM raises comes from one place: adm_error, and adm_ai_error for the AI Pack. Each has a stable number, a category and a named exception, so your own code can react to what went wrong instead of matching on message text.

Pick the loosest one that does what you need — a named exception when you care about one specific failure, a category when a whole class of failures gets the same treatment.

begin
adm_document_api.trash_document(p_document_id => l_id);
exception
when adm_error.e_legal_hold_active then
-- the document is on hold; tell the user and carry on
apex_error.add_error(
p_message => 'This document is under legal hold and cannot be deleted.'
, p_display_location => apex_error.c_inline_in_notification
);
end;

Every code belongs to exactly one category, so you do not have to enumerate codes:

begin
adm_document_api.rename_document(p_document_id => l_id, p_new_name => l_name);
exception
when others then
if adm_error.is_no_permission(sqlcode) then
log_denied_attempt(l_id);
elsif adm_error.is_not_found(sqlcode) then
refresh_the_grid;
elsif adm_error.is_conflict(sqlcode) then
suggest_another_name(l_name);
else
raise;
end if;
end;

The predicates are is_not_found, is_no_permission, is_conflict, is_invalid_input and is_invalid_state. get_category returns the category itself, and each predicate returns a definite true or false — never null — so if not adm_error.is_not_found(...) behaves the way it reads.

These work for AI Pack codes too, without the AI Pack being installed:

if adm_error.is_not_found(sqlcode) then ... -- true for ORA-20600 as well

Tell ADM errors apart from everything else

Section titled “Tell ADM errors apart from everything else”
exception
when others then
if adm_error.is_adm_error(sqlcode) then
-- ADM refused this on purpose; the message is written for the end user
show_message(adm_error.strip_ora_prefix(sqlerrm));
else
raise; -- a genuine Oracle error, or another product's
end if;
end;

is_adm_error is narrow: it is false for the bundled UC plugin libraries and for uc_ai, even though those also raise in the -20000 .. -20999 application range. See Number ranges.

Hook PL/SQL and your own packages are yours: raise with plain raise_application_error. Use a number from -20700 .. -20999, which ADM reserves for you and will never claim:

if lower(l_document_name) like '%virus%' then
raise_application_error(-20700, 'Upload aborted: the file appears to be infected.');
end if;

Do not raise ADM’s own codes from your code. A caller that catches adm_error.e_doc_not_found should be able to trust that ADM raised it.

Register the supplied error handling function on your application under Edit Application Properties → Error Handling → Error Handling Function:

adm_error.apex_error_handler

With it in place:

  • ADM errors written for end users are shown as they are, without the ORA-nnnnn: prefix.
  • Errors in the INTERNAL and EXTERNAL categories are replaced by a generic sentence, because their text names internal identifiers, storage keys and HTTP endpoints. The original stays in the APEX debug log.
  • A unique constraint ADM owns becomes a sentence (“A document with this name already exists in this folder.”) instead of ORA-00001: unique constraint (…) violated.
  • Anything else is left to APEX, except that an internal error is replaced by the same generic sentence.

Without it, every message reaches the user raw, as ORA-20140: Document not found: 42.

ADM shares its schema with the bundled UC plugin libraries and, for the AI Pack, with uc_ai. All of them raise in the same -20000 .. -20999 application range, so the range map is what makes a number attributable:

RangeOwner
-20000 .. -20099The bundled UC plugin libraries (uc_prp, uc_rte, uc_sbp use -20010 .. -20020; AOP uses -20001, -20002)
-20100 .. -20299ADM base product — see the table below
-20300 .. -20599uc_ai, the AI Pack dependency
-20600 .. -20699ADM AI Pack
-20700 .. -20999Yours. Hook code and anything else you write in this schema

A bare number is not attributable on its own, which is why adm_error.is_adm_error exists: -20012 from ADM and -20012 from a UC plugin would be indistinguishable, so ADM does not use that range at all.

Messages below show their apex_string.format placeholders (%0, %1, …); at runtime those are filled in.

CodeConstantCategoryMessage
ORA-20100adm_error.c_err_missing_paramINVALID_INPUT%0 is required
ORA-20101adm_error.c_err_invalid_paramINVALID_INPUTInvalid %0: %1
ORA-20102adm_error.c_err_invalid_nameINVALID_INPUT%0 %1
ORA-20103adm_error.c_err_invalid_usernameINVALID_INPUTUsername %0
ORA-20104adm_error.c_err_not_foundNOT_FOUND%0 not found: %1
ORA-20105adm_error.c_err_already_existsCONFLICT%0 “%1” already exists
ORA-20106adm_error.c_err_invalid_stateINVALID_STATE%0
ORA-20107adm_error.c_err_not_supportedINVALID_INPUTUnsupported %0: %1
ORA-20108adm_error.c_err_limit_exceededINVALID_INPUT%0 (%1) exceeds the maximum of %2
ORA-20109adm_error.c_err_hook_failedINTERNALThere was an error processing the %0. Please contact the administrator(s).
ORA-20110adm_error.c_err_internalINTERNALAn unexpected error occurred in %0. Please contact your administrator.
ORA-20111adm_error.c_err_data_integrityINTERNALInconsistent data: %0
CodeConstantCategoryMessage
ORA-20120adm_error.c_err_admin_requiredNO_PERMISSIONOnly administrators can %0.
ORA-20121adm_error.c_err_no_permissionNO_PERMISSIONYou do not have permission to %0.
ORA-20122adm_error.c_err_no_view_rightNO_PERMISSIONYou do not have view rights on %0.
ORA-20123adm_error.c_err_no_edit_rightNO_PERMISSIONYou do not have edit rights on %0.
ORA-20124adm_error.c_err_no_contextINVALID_STATENo ADM session context is established. Log in through adm_context_api first.
ORA-20125adm_error.c_err_invalid_credentialsNO_PERMISSIONYou have entered an invalid link or password.
ORA-20126adm_error.c_err_expiredNO_PERMISSIONThe link has expired. Please contact the document owner.
ORA-20127adm_error.c_err_token_invalidNO_PERMISSIONThe token is not valid.
ORA-20128adm_error.c_err_user_not_foundNOT_FOUNDUser not found: %0
ORA-20129adm_error.c_err_user_existsCONFLICTUser already exists: %0
ORA-20130adm_error.c_err_group_not_foundNOT_FOUNDGroup not found: %0
ORA-20131adm_error.c_err_role_invalidINVALID_INPUTInvalid role: %0
CodeConstantCategoryMessage
ORA-20140adm_error.c_err_doc_not_foundNOT_FOUNDDocument not found: %0
ORA-20141adm_error.c_err_doc_deletedINVALID_STATEDocument %0 has been deleted.
ORA-20142adm_error.c_err_doc_existsCONFLICTA document with the name “%0” already exists in this folder.
ORA-20143adm_error.c_err_doc_trash_ruleINVALID_STATE%0
ORA-20144adm_error.c_err_version_not_foundNOT_FOUNDDocument version not found: %0
ORA-20145adm_error.c_err_no_current_versionINVALID_STATEDocument %0 has no current version.
ORA-20146adm_error.c_err_content_unavailableINVALID_STATEFile content could not be retrieved for version %0.
ORA-20147adm_error.c_err_not_an_archiveINVALID_INPUTDocument %0 is not a ZIP archive.
ORA-20148adm_error.c_err_archive_emptyINVALID_STATENothing to %0: %1 contains no files.
ORA-20149adm_error.c_err_upload_not_foundNOT_FOUNDUpload not found or no longer available: %0
ORA-20150adm_error.c_err_upload_stateINVALID_STATE%0
CodeConstantCategoryMessage
ORA-20170adm_error.c_err_folder_not_foundNOT_FOUNDFolder not found: %0
ORA-20171adm_error.c_err_folder_deletedINVALID_STATEFolder %0 has been deleted.
ORA-20172adm_error.c_err_folder_existsCONFLICTA folder with the name “%0” already exists in %1.
ORA-20173adm_error.c_err_folder_systemINVALID_STATESystem folders cannot be %0.
ORA-20174adm_error.c_err_folder_trash_ruleINVALID_STATE%0
ORA-20175adm_error.c_err_folder_cycleINVALID_INPUTA folder cannot be moved into itself or one of its own descendants.
ORA-20176adm_error.c_err_folder_has_protectedINVALID_STATEThis folder contains %0 document(s) under legal hold or a retention policy, so it cannot be permanently deleted.
CodeConstantCategoryMessage
ORA-20190adm_error.c_err_legal_hold_activeINVALID_STATEDocument %0 is under legal hold.
ORA-20191adm_error.c_err_legal_hold_missingINVALID_STATEDocument %0 does not have a legal hold.
ORA-20192adm_error.c_err_retention_activeINVALID_STATEDocument %0 has a retention policy that has not expired.
ORA-20193adm_error.c_err_retention_missingINVALID_STATEDocument %0 does not have a retention policy.
ORA-20194adm_error.c_err_retention_invalidINVALID_INPUTInvalid retention setting: %0
CodeConstantCategoryMessage
ORA-20200adm_error.c_err_share_not_foundNOT_FOUNDShare not found: %0
ORA-20201adm_error.c_err_share_invalidINVALID_INPUTInvalid share configuration: %0
ORA-20202adm_error.c_err_embed_invalidINVALID_INPUTInvalid embed request: %0
ORA-20203adm_error.c_err_embed_perm_invalidINVALID_INPUTInvalid embed permissions: %0
ORA-20204adm_error.c_err_embed_grant_unknownINVALID_INPUTUnknown embed grant: %0
CodeConstantCategoryMessage
ORA-20220adm_error.c_err_tag_not_foundNOT_FOUNDTag not found: %0
ORA-20221adm_error.c_err_tag_not_assignedINVALID_STATETag %0 is not assigned to this document.
ORA-20222adm_error.c_err_tag_existsCONFLICTThis document already carries the tag %0.
ORA-20223adm_error.c_err_annotation_not_foundNOT_FOUNDAnnotation “%0” does not exist for document %1.
ORA-20224adm_error.c_err_annotation_existsCONFLICTAnnotation “%0” already exists for document %1.
ORA-20226adm_error.c_err_tag_ambiguousINVALID_STATETag %0 is assigned to this document more than once. Address a single assignment through the document_tag_id overload.
ORA-20225adm_error.c_err_taxonomy_invalidINVALID_INPUTInvalid taxonomy configuration: %0
CodeConstantCategoryMessage
ORA-20230adm_error.c_err_storage_not_configuredINVALID_STATEObject storage is not configured: %0 is missing.
ORA-20231adm_error.c_err_storage_disabledINVALID_STATEObject storage is not enabled.
ORA-20232adm_error.c_err_storage_requestEXTERNALObject storage request failed: %0
ORA-20233adm_error.c_err_storage_key_missingINVALID_STATEObject storage key is missing for %0.
ORA-20234adm_error.c_err_storage_migrationINVALID_STATE%0
ORA-20235adm_error.c_err_policy_not_foundNOT_FOUNDStorage policy not found: %0
ORA-20236adm_error.c_err_policy_existsCONFLICTA storage policy already exists for %0.
ORA-20237adm_error.c_err_cleanup_not_foundNOT_FOUNDStorage cleanup record not found: %0
ORA-20238adm_error.c_err_checksum_mismatchINTERNALChecksum mismatch for %0.
ORA-20239adm_error.c_err_storage_credentialsINVALID_STATENo valid Web Credentials found. Please go to Shared Components > Web Credentials and set up the OCI connection.
CodeConstantCategoryMessage
ORA-20260adm_error.c_err_setting_not_foundNOT_FOUNDSetting not found: %0
ORA-20261adm_error.c_err_setting_invalidINVALID_INPUTInvalid value for setting %0: %1
ORA-20262adm_error.c_err_job_failedINTERNALAn error occurred during the %0 job execution. Please check the logs for details.
ORA-20263adm_error.c_err_aop_not_configuredINVALID_STATEAOP is not configured. Please contact your administrator.
ORA-20264adm_error.c_err_conversion_failedEXTERNAL%0 conversion failed.
ORA-20265adm_error.c_err_search_invalidINVALID_INPUTInvalid search request: %0

Codes here are grouped by category, in fixed sub-ranges, rather than by domain: adm_error ships in the base product and must work with the AI Pack absent, so it works out an AI Pack code’s category arithmetically from where the code sits instead of holding a list of them.

Sub-rangeCategory
-20600 .. -20609NOT_FOUND
-20610 .. -20624INVALID_INPUT
-20625 .. -20634INVALID_STATE
-20635 .. -20644EXTERNAL
-20645 .. -20649INTERNAL
CodeConstantCategoryMessage
ORA-20600adm_ai_error.c_err_collection_not_foundNOT_FOUNDRAG collection not found: %0
ORA-20601adm_ai_error.c_err_chunk_not_foundNOT_FOUNDRAG chunk not found: %0
ORA-20602adm_ai_error.c_err_queue_entry_not_foundNOT_FOUNDNo RAG job queue entry for %0
ORA-20603adm_ai_error.c_err_debug_log_not_foundNOT_FOUNDRAG debug log entry not found: %0
CodeConstantCategoryMessage
ORA-20610adm_ai_error.c_err_config_invalidINVALID_INPUTInvalid %0: %1
ORA-20611adm_ai_error.c_err_config_missingINVALID_INPUT%0 requires %1
ORA-20612adm_ai_error.c_err_config_not_jsonINVALID_INPUTThe configuration is not valid JSON.
ORA-20613adm_ai_error.c_err_chunk_configINVALID_INPUTInvalid chunk configuration: %0
ORA-20614adm_ai_error.c_err_unsupported_valueINVALID_INPUTUnsupported %0: “%1”. Allowed values are %2.
ORA-20615adm_ai_error.c_err_missing_paramINVALID_INPUT%0 is required
CodeConstantCategoryMessage
ORA-20625adm_ai_error.c_err_no_vector_supportINVALID_STATEThe native Oracle vector store needs Oracle 23ai or newer. This database is %0. Use the Qdrant vector store instead.
ORA-20626adm_ai_error.c_err_vector_storeINVALID_STATEThe vector store is not usable: %0
ORA-20627adm_ai_error.c_err_no_contentINVALID_STATEThere is no content to work with: %0
ORA-20628adm_ai_error.c_err_wrong_job_typeINVALID_STATEA %0 job was queued but the collection has no %1 configuration.
ORA-20629adm_ai_error.c_err_vector_dims_immutableINVALID_STATEThe vector store for collection %0 was built with %1 dimensions and cannot be changed to %2. Recreate the collection.
CodeConstantCategoryMessage
ORA-20635adm_ai_error.c_err_qdrant_requestEXTERNALThe Qdrant request failed: %0
ORA-20636adm_ai_error.c_err_embeddingEXTERNALEmbedding failed: %0
ORA-20637adm_ai_error.c_err_extractionEXTERNALText extraction failed: %0
ORA-20638adm_ai_error.c_err_extraction_truncatedEXTERNALThe model stopped before the document ended (finish_reason=length). Raise the token limit or split the document.
ORA-20639adm_ai_error.c_err_generationEXTERNALAnswer generation failed: %0
CodeConstantCategoryMessage
ORA-20645adm_ai_error.c_err_internalINTERNALAn unexpected error occurred in %0. Please contact your administrator.
ORA-20646adm_ai_error.c_err_job_failedINTERNALAn error occurred during the %0 job execution. Please check the logs for details.
CategoryMeansTypical response
NOT_FOUNDThe thing was not there, or is deletedRefresh, or tell the user it is gone
NO_PERMISSIONThe current user may not do thisHide the action; log the attempt
INVALID_INPUTThe arguments were wrongShow the message; it names what to fix
INVALID_STATEThe object exists but not in a usable stateShow the message; the state has to change first
CONFLICTSomething with that name or key already existsOffer another name, or merge
EXTERNALA service outside the database failed (object storage, Qdrant, an LLM)Retry; the detail is in the log
INTERNALA bug or a broken invariantShow nothing specific; read the log

adm_error.apex_error_handler replaces EXTERNAL and INTERNAL messages before a user sees them.

Error codes were renumbered in 26.1, and code that catches ADM errors by number has to be updated. What changed, what to replace it with, and where hook code should raise its own errors is in What changed in 26.1 → Errors.