Definition
CFTRY and CFCATCH are ColdFusion Markup Language (CFML) tags used for exception handling. They work together to safely run code that might fail and to respond gracefully if an error occurs. Think of
In practical terms,
How It Works
Core Concept
- Put risky operations inside
. - Handle specific errors inside one or more
blocks (by type). - Optionally add
to run code that should always execute (e.g., closing files, releasing locks).
Control flow (Step-by-Step)
- ColdFusion executes code inside
. - If no exception occurs, ColdFusion skips all
blocks and moves to (if present), then continues. - If an exception occurs, ColdFusion checks each
in order to find a match by type. - The first matching
runs. If none match, a more general catch like type=”any” (or no match) will handle or bubble the error. - After
, executes if present.
Syntax Overview
Basic structure:
Common Types
Use specific types first to avoid masking critical problems:
- application: For application-level exceptions
- database: SQL errors (query, stored procedures, timeouts)
- Security: Permission and authorization issues
- template: Template parsing or compilation errors
- expression: Expression evaluation failures (division by zero, etc.)
- missinginclude: Missing included templates
- object: CFC instantiation and method-calling errors
- type: Type coercion or parameter type mismatches
- lock: Locking timeouts
- any: Catch-all for exceptions not matched by earlier types
Tip: In Adobe ColdFusion and Lucee, the exact set of types and their behavior may vary slightly. Always consult your engine’s documentation.
Practical Syntax Examples
Example 1: Handling Database Exceptions
SELECT * FROM Users WHERE UserID =
Example 2: Always Clean Up With
Real-World Use Case: Upload, Validate, Save, and Roll Back Safely
Imagine a feature where a user uploads a product image and details, which you then save to disk and insert into a database. A failure in any step should not leave partial data behind.
<!--- 2) Validate metadata --->
<cfif len(trim(form.productName)) EQ 0>
<cfthrow type="validation" message="Product name is required.">
</cfif>
<!--- 3) Save to DB --->
<cfquery name="qInsert" datasource="MyDSN">
INSERT INTO Products (Name, ImagePath, Price)
VALUES (
<cfqueryparam value="#form.productName#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#uploadedPath#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#form.price#" cfsqltype="cf_sql_decimal">
)
</cfquery>
<cftransaction action="commit">
</cftransaction>
<cfcatch type="validation">
<cftransaction action="rollback">
<!--- Remove uploaded file since DB insert failed --->
<cfif fileExists(expandPath('/uploads/' & uploadedPath))>
<cffile action="delete" file="#expandPath('/uploads/' & uploadedPath)#">
</cfif>
<cfset request.userMessage = "Please fix: #cfcatch.message#">
</cfcatch>
<cfcatch type="database">
<cftransaction action="rollback">
<cflog file="app" text="DB error inserting product: #cfcatch.detail#">
<!--- Remove uploaded file on DB failure --->
<cfif structKeyExists(variables, "uploadedPath") AND fileExists(expandPath('/uploads/' & uploadedPath))>
<cffile action="delete" file="#expandPath('/uploads/' & uploadedPath)#">
</cfif>
<cfset request.userMessage = "Could not save your product. Try again later.">
</cfcatch>
<cfcatch type="any">
<cftransaction action="rollback">
<cflog file="app" text="Unhandled error: #cfcatch.message#">
<cfset request.userMessage = "An unexpected error occurred.">
</cfcatch>
<cffinally>
<!--- Additional cleanup or metrics --->
</cffinally>
This pattern ensures that Validation errors, database failures, and unexpected exceptions are each handled appropriately, and that partial work (such as an uploaded file) doesn’t remain after a failure.
Use Cases
Database Operations
- Wrap queries and stored procedures to catch timeouts or constraint violations.
- Combine with cftransaction to consistently roll back on errors.
- Log query parameters (sanitized) for Troubleshooting.
File I/O
- Handle file not found, permission errors, and path issues with cffile operations.
- Delete temporary files inside
or always clean up in .
External Services and APIs
- Use cfhttp for REST calls inside
. - Catch timeouts, 4xx/5xx HTTP status codes, and JSON parsing errors.
- Retry transient failures (with backoff) and surface friendly messages.
Data Validation and Business Rules
- Throw custom exceptions with cfthrow when rules fail.
- Catch with a specific type like type=”validation” to show user feedback.
Best practices
- Prefer specific catch types before type=”any” to avoid hiding real issues.
- Always log critical information: cfcatch.message, cfcatch.detail, cfcatch.stackTrace (where available), and cfcatch.tagContext.
- Use
for guaranteed cleanup (closing resources, unlocking, clearing temp data). - Don’t swallow exceptions silently. If you handle it, either provide a user message, log it, or rethrow with cfthrow.
- Use cftransaction around related DB operations and roll back on exceptions.
- Sanitize logs: avoid logging sensitive data (passwords, tokens).
- Keep try blocks small. Narrow scope improves clarity and reduces accidental masking.
- For application-wide errors, use Application.cfc onError() or cferror alongside local try/catch.
- When integrating with components, document which methods throw which types and handle them at call sites.
Comparison With Other ColdFusion Error-Handling Features
| Feature | Scope | When to Use | Notes |
|---|---|---|---|
| CFTRY/CFCATCH/CFFINALLY | Local block | Fine-grained handling around risky code | Most common pattern; supports typed catches |
| Application.cfc onError | App-wide | Centralized catch for uncaught errors | Great for logging, alerts, custom responses |
| CFERROR | Request or site level | Legacy/global error pages | Useful fallback; less flexible than try/catch |
| Server error templates | Server-level | Last-resort user-friendly pages | Not app-specific; minimal context |
Key takeaway: Use CFTRY/CFCATCH for precise, local handling; fall back to Application.cfc or cferror to catch what slips through.
Advanced Tips and Patterns
Rethrowing and Custom Exceptions
- Use cfthrow inside a
to rethrow with more context. - Create custom types (e.g., type=”validation” or type=”billing.PaymentDeclined”) to structure your error taxonomy.
Observability and Alerting
- Include request IDs, user IDs, or correlation IDs in logs to cross-reference across systems.
- Consider email or webhook alerts on critical exceptions.
Performance Considerations
- Exceptions are relatively expensive. Avoid using try/catch to control normal flow; reserve for exceptional conditions.
- Keep the risky code minimal within the try block.
Working With Lucee vs. Adobe ColdFusion
- Both support try/catch/finally, but certain cfcatch struct keys and exception types can differ.
- Test behavior in your target engine and version; consult release notes for changes in exception structures.
Key Points
- CFTRY and CFCATCH provide structured, typed exception handling in CFML.
- Add CFFINALLY to guarantee cleanup.
- Catch the most specific types first, then fall back to type=”any”.
- Combine with cftransaction, cflog, and cfthrow for robust Error handling.
- Use Application.cfc onError or cferror for global safety nets.
FAQ
What information is available inside cfcatch?
The cfcatch variable is a struct that typically includes keys like message, detail, type, tagContext, errorCode, and sometimes stackTrace. Availability depends on the CFML engine and the error type.
How do I catch multiple types differently?
Add multiple
When should I use cferror or Application.cfc onError instead of cftry/cfcatch?
Use cftry/cfcatch for local, fine-grained handling around code that might fail. Use Application.cfc onError or cferror for uncaught exceptions or to provide centralized logging and user-friendly error pages.
Is cffinally required?
No, but it is recommended. Use
