Send Docs Feedback

Fault handling

Many error conditions can arise while API proxies are servicing requests from apps. For example, API proxies might encounter network issues when communicating with backend services, apps might present expired credentials, request messages might be incorrectly formatted, and so on. In many cases, you will need to handle such errors in a customized fashion. This topic shows you how to set up custom fault handling in Apigee Edge.

About errors

When an API proxy encounters an error, the default behavior of the API proxy is to exit the normal processing pipeline, meaning exit the current flow, and to enter an Error flow. Once the API proxy enters the Error flow, it cannot return processing back to the normal flow pipeline.

By entering the Error flow, the proxy:

  • Bypasses any remaining processing steps, meaning any remaining policies, in the current flow
  • Bypasses any subsequent flows
  • Returns a fault response to the requesting app.

This process results in a raw error message or error codes being returned to the requesting app.

Types of errors

An API proxy can encounter the following categories of errors:

  • Messaging: Failures arising while driving the message flow, not including policy errors, such as routing failures
  • Policy: Failures arising while processing any policies
  • Transport: Failures occurring in the transport layer, such as HTTP errors due to protocol level failures or SSL errors
  • System: Failures in the underlying system, such as out of memory errors

For more information on these errors, see Fault taxonomy below.

You can also use the Raise Fault policy to generate an error, typically based on a condition. You can use the Raise Fault policy to define a fault response that is returned to the requesting app when a specific condition arises. 

Controlling how a policy reacts to an error

For all errors other than policy errors, an API proxy immediately enters the Error flow. For policy errors, meaning failures arising while processing a policy, the continueOnError element of a policy controls the way the API proxy reacts to an error.

By default, the continueOnError element is false, meaning that when a fault occurs in a policy, control is directed to the Error flow. For example, the following VerifyAPIKey policy uses the default value of the continueOnError element:

<VerifyAPIKey async="false" continueOnError="false" enabled="true" name="verify-api-key">
  <DisplayName>Verify API Key</DisplayName>
  <APIKey ref="request.queryparam.apikey"/>
</VerifyAPIKey>

If you set the continueOnError element to true, control stays in the current flow of the API proxy and the next policy in the pipeline executes.

Creating fault rules

In many cases you want to control the response of your API proxy to an error. For example, you might want to send a custom error message when a developer app exceeds a Quota, add more information about the error to the response, remove information from the response not meant to be seen by the calling app, or to modify the response in other ways to improve usability and security.

Apigee Edge enables you to customize error handling by defining fault rules. A fault rule specifies two items:

  • A Condition that specifies the fault to be handled based on the pre-defined category, subcategory, or name of the fault
  • One or more policies that define the behavior of the fault rule for the corresponding Condition.

    Often you use a single AssignMessage policy in a fault rule that overrides the default message generated for a fault and inserts a customized error message. Usually fault rules do not not themselves include the Raise Fault policy unless you want to raise another fault for some reason as part of handling the fault. 

Attach fault rules to the following entities in an API proxy configuration:

  • ProxyEndpoint: Enables fault handling for all errors that occur in the ProxyEndpoint request and response flows.
  • TargetEndpoint: Enables fault handling for all errors that occur in the TargetEndpoint request and response flows.

To add a fault rule you need to edit the XML configuration of the ProxyEndpoint or TargetEndpoint. You can use the Edge UI to make this edit in the Code pane of the Develop view for an API proxy, or edit the XML file that defines the ProxyEndpoint or TargetEndpoint.

The basic structure of a fault rule is shown below:

<FaultRules>
  <FaultRule>
    <Step>
      <Name>{policy_name}</Name>
    </Step>
    <Condition>{(conditional statement)}</Condition>
  </FaultRule>

  <FaultRule>
    ...
  </FaultRule>
</FaultRules>      

or:

<FaultRules>
  <FaultRule>
    <Step>
      <Name>{policy_name}</Name>
      <Condition>{(conditional statement)}</Condition>
    </Step>
  </FaultRule>

  <FaultRule>
    ...
  </FaultRule>
</FaultRules>

where the <Condition> applies to the entire fault rule or only to a specific step in the fault rule. You can define multiple fault rules in a ProxyEndpoint or TargetEndpoint to handle multiple fault conditions.

When a fault rule's condition evaluates to true, the policies specified in the rule execute. If multiple fault rules have a condition that evaluates to true, then the last of those fault rules executes. This is different behavior from Route Rules and Flow conditions, which execute the first of the set for which a condition evaluates to true.

See Flow variables and conditions for more on how to configure conditions.

Specifying the condition on a fault rule

Each type of error defines a set of error codes that it creates in response to an error. For policy errors, you can find the error codes for each policy in the policy reference, starting with the Policy reference overview.

All policy error codes have the same format, as shown in the example below:

{
  "code" : " {error.code} ",
  "message" : " {Error message} ",
  "contexts" : [ ]
}

For example, when a developer app presents and invalid consumer key, the VerifyApiKey policy returns the following error code:

{
  "code" : " InvalidApiKey ",
  "message" : "The consumer key presented by the app is invalid.",
  "contexts" : [ ]
}

Use the error code to define the condition the defines the fault rule to execute. The fault.name variable contains the value of the code field of the error code. You then use the fault.name variable in the <Condition> tag, as the following example shows:

<ProxyEndpoint name="default">
  ...
  <FaultRules>
    <FaultRule name="invalid_key_rule">
      <Step>
        <Name>{policy_name}</Name>
      </Step>
      <Condition>(fault.name = "InvalidApiKey")</Condition>
    </FaultRule>
  </FaultRules>
</ProxyEndpoint>

This fault rule executes if an error code InvalidApiKey is thrown by the VerifyApiKey policy.

One common configuration of an API proxy is to use the Quota policy to set the number of requests that an app is allowed to submit to an API proxy over a time period. If the app exceeds the allowed quota, then the Quota policy issues an error where the the value of the code field is QuotaViolation. You can use the following condition in a fault rule to detect the quota error:

<FaultRule name="quota_rule1">
  <Step>
    <Name>{policy_name}</Name>
  </Step>
  <Condition>(fault.name = "QuotaViolation")</Condition>
</FaultRule>
If multiple fault rules have a condition that evaluates to true, then the last of those fault rules executes.

Adding policies to a fault rule

Now that you have configured a fault rule, you need to add a policy to the rule to handle the error. This policy then determines the action of the fault rule.

While you can put any policy in the fault rule, you commonly use the Assign Message policy. Use the Assign Message policy to generates a custom response message for an error condition. Assign Message enables you to configure an HTTP response with payload, HTTP status code, headers, and reason phrase elements.

A policy used in a fault rule is typically not used in the normal flow pipeline. Therefore, when using the Edge UI to create a policy for a fault rule, select the plus sign, "+", next to "Policies" in the UI to add the policy:

The example below shows a typical Assign Message policy configuration:

<AssignMessage name="fault_invalidkey">
  <Set>
      <Payload contentType="text/plain">Contact support at support@mycompany.com.</Payload>
      <StatusCode>401</StatusCode>
      <ReasonPhrase>Unauthorized</ReasonPhrase>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

You can now use this policy in your fault rule. Notice how you reference the Assign Message policy by name in the fault rule:

<ProxyEndpoint name="default">
  ...
  <FaultRules>
    <FaultRule name="invalid_key_rule">
      <Step>
        <Name>fault_invalidkey</Name>
      </Step>
      <Condition>(fault.name = "InvalidApiKey")</Condition>
    </FaultRule>
  </FaultRules>
</ProxyEndpoint>

When you deploy the configuration above, the API proxy will execute the Assign Message policy called fault_invalidkey whenever an app presents and invalid API key.

You can execute multiple policies in a fault rule, as the following example shows:

<ProxyEndpoint name="default">
  ...
  <FaultRules>
    <FaultRule name="invalid_key_rule">
      <Step>
        <Name>policy1</Name>
      </Step>
      <Step>
        <Name>policy2</Name>
      </Step>
      <Step>
        <Name>policy3</Name>
      </Step>
      <Condition>(fault.name = "InvalidApiKey")</Condition>
    </FaultRule>
  </FaultRules>
</ProxyEndpoint>

The policies execute in the order defined. For example, you can use the Message Logging policy, the Extract Variables policy, the Assign Message policy, or any other policy in the fault rule. Note that processing of the fault rule stops immediately if either of these situations occur:

  • Any policy in the fault rule causes an error
  • Any of the policies in the fault rule is of type Raise Fault

Defining the custom error message returned from a fault rule

As a best practice, you should define a rules that determine the error responses from your APIs. In that way, you deliver consistent and helpful information your clients. For more on defining consistent error messages, see RESTful API Design: what about errors?.

The example Assign Message policy below uses the <Payload>, <StatusCode>, and <ReasonPhase> tags to define the custom error response sent back to the client:

<AssignMessage name="fault_invalidkey">
  <FaultResponse>
    <Set>
      <Payload contentType="text/plain">You have attempted to access a resource without the correct authorization. 
         Contact support at support@mycompany.com.</Payload>
      <StatusCode>401</StatusCode>
      <ReasonPhrase>Unauthorized</ReasonPhrase>
    </Set>
  </FaultResponse>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

This response includes:

  • The payload containing the error message and an email address for contacting support.
  • The HTTP status code returned in the response.
  • The reason phrase, which is a short description of the error.

Creating a default fault rule

A default fault rule acts an exception handler for any error that is not explicitly handled by another fault rule. If the conditions for all fault rules do not match the error, then the default fault rule handles the error. Default fault handling can be enabled by adding the <DefaultFaultRule> tag as a child element of a ProxyEndpoint or a TargetEndpoint.

If a fault rule other than the default fault rule invokes a Raise Fault policy, the default fault rule does not execute, even if the <AlwaysEnforce> element in the <DefaultFaultRule> tag is true.

For example, the TargetEndpoint configuration below defines a default fault rule that invokes a policy named ReturnGenericError:

<TargetEndpoint name="default">
  ...
  <FaultRules>
    ...
  </FaultRules>

  <DefaultFaultRule name="fault-rule">
    <Step>
      <Name>ReturnGenericError</Name>
    </Step>
  </DefaultFaultRule>

  <HTTPTargetConnection>
    <URL>http://weather.yahooapis.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

The default fault rule is typically used to return a generic error message for any unexpected error, such as a message that contains contact information for technical support. This default response serves the dual purpose of providing developer-friendly information while also obfuscating backend URLs or other information that might be used to compromise the system.

For example, you define the following AssignMessage policy to return a generic error:

<AssignMessage name="ReturnGenericError">
  <Set>
    <Payload type="text/plain">SERVICE UNAVAILABLE. PLEASE CONTACT SUPPORT: support@company.com.</Payload>
  </Set>
</AssignMessage>

Include the <AlwaysEnforce> element in the <DefaultFaultRule> tag to execute the default fault rule for every error, even if another fault rule has already been executed. The default fault rule is always the last fault rule to execute:

  <DefaultFaultRule name="fault-rule">
    <Step>
      <Name>ReturnGenericError</Name>
    </Step>
    <AlwaysEnforce>true</AlwaysEnforce>
  </DefaultFaultRule>

One use of the default fault rule is to determine the type of error that occurs when you otherwise cannot determine it. For example, your API proxy is failing for an error that you cannot determine. Use the default fault rule to invoke the following AssignMessage policy. This policy writes the fault.name value to a header named DefaultFaultHeader in the response:

<AssignMessage async="false" continueOnError="false" enabled="true" name="DefaultFaultRule">
  <DisplayName>DefaultFaultRule</DisplayName>
  <Set>
    <Headers>
      <Header name="DefaultFaultHeader">{fault.name}</Header>
    </Headers>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

You can then view the header in the Edge trace tool or on the response to see what caused the error.

Handling policy faults within the current flow

The examples shown so far all use a fault rule on the ProxyEndpoint or TargetEndpoint to handle any policy errors as part of the Error flow. That is because the default value of the continueOnError element of a policy is false, meaning that when an error occurs in a policy, control is directed to the Error flow. Once in the Error flow, you cannot return control back to the normal pipeline and you typically return some form of error message to the calling app.

However, if you set the continueOnError element to true for a policy, control stays in the current flow and the next policy in the pipeline executes after the policy that caused the error. The advantage to handling the error in the current flow is that you might have a way to recover from the error to complete processing of the request.

Shown below is a VerifyAPIKey policy named verify-api-key with the continueOnError element set to true:

<VerifyAPIKey async="false" continueOnError="true" enabled="true" name="verify-api-key">
  <DisplayName>Verify API Key</DisplayName>
  <APIKey ref="request.queryparam.apikey"/>
</VerifyAPIKey>

If the API key is missing or invalid, then the VerifyAPIKey policy sets the verifyapikey.verify-api-key.failed variable to true, but processing continues in the current flow.

You then add VerifyAPIKey policy as a step in the PreFlow of the ProxyEndpoint:

<ProxyEndpoint name="default">
  ...
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>verify-api-key</Name>
      </Step>
      <Step>
        <Name>FaultInFlow</Name>
        <Condition>(verifyapikey.verify-api-key.failed = "true")</Condition>
      </Step>
    </Request>
    <Response/>
  </PreFlow>	
</ProxyEndpoint>	

Notice how the next step in the PreFlow uses a condition to test for the existence of an error. If an error occurred in the VerifAPIKey policy, then the policy named FaultInFlow policy executes. Otherwise, the FaultInFlow policy is skipped. The FaultInFlow policy can do many things, such as logging the error, attempting to fix the error, or performing some other action.

Triggering an error by using the Raise Fault policy

You can use the Raise Fault policy at any time in a flow to trigger an error. When a Raise Fault policy executes, it terminates the current flow and transfers control to the Error flow.

One use of the Raise Fault policy is to test for a specific condition that another policy might not detect. In the example above, you added a <Condition> tag to a PreFlow <Step> tag that caused the policy FaultInFlow to execute if the condition is met. If FaultInFlow is a Raise Fault policy, then control transfers to the Error flow. Or, you might insert a Raise Fault policy in a flow to debug and test your fault rules.

When a Raise Fault policy triggers an error, you can use the following fault rule and condition to process it:

<FaultRule name="raisefault_rule">
  <Step>
    <Name>{policy_name}</Name>
  </Step>
  <Condition>(fault.name = "RaiseFault")</Condition>
</FaultRule>

Note that the condition tests for a fault named RaiseFault.

Custom handling of HTTP error codes from the target server

The examples shown in the previous sections apply to errors created by policies. However you can also create a custom response for transport-level errors, meaning HTTP errors returned from the target server. To control the response from an HTTP error, configure a TargetEndpoint to process HTTP response codes.

By default, Edge treats HTTP response codes in the 1xx-3xx range as 'success', and HTTP response codes in the range 4xx-5xx as 'failure'. That means any response from the backend service with an HTTP response code 4xx-5xx automatically invokes the Error flow, which then returns an error message directly to the requesting client.

You can create custom handlers for any HTTP response codes. For example, you might not want to treat all HTTP response codes in the range 4xx-5xx as 'failure' but only 5xx, or you might want to return custom error messages for HTTP response codes 400 and 500.

In the next example, you use the success.codes property to configure the TargetEndpoint to treat HTTP response codes 400 and 500 as a success, along with the default HTTP codes. By treating those codes as a success, the TargetEndpoint takes over the processing of the response message, instead of invoking the Error flow:

<TargetEndpoint name="default">
  ...
  <HTTPTargetConnection>
    <Properties>
	  <Property name="success.codes">1xx,2xx,3xx,400,500</Property>
    </Properties>
    <URL>http://weather.yahooapis.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

As you can see in this example, you can use wildcards to set the success.codes property to a range of values.. 

Setting the success.codes property overwrites the default values. Therefore, if you want to add HTTP code 400 to the list of default success codes, set this property as:

<Property name="success.codes">1xx,2xx,3xx,400</Property>

But, if you only want HTTP code 400 to be treated as a success code, set the property as:

<Property name="success.codes">400</Property>

You can now define custom handlers for HTTP response codes 400 and 500 to return a customized response message to the requesting app. The following TargetEndpoint uses the policy named ReturnError to handle HTTP 400 and 500 response codes:

<TargetEndpoint name="default">
  <PreFlow name="PreFlow">
    <Request/>
    <Response>
      <Step>
        <Name>ReturnError</Name>
        <Condition>(response.status.code = 400) or (response.status.code = 500)</Condition>
      </Step>
    </Response>
  </PreFlow>

  <HTTPTargetConnection>
    <Properties>
      <Property name="success.codes">1xx,2xx,3xx,400,500</Property>
    </Properties>
    <URL>http://weather.yahooapis.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

This TargetEndpoint configuration causes the policy called ReturnError to handle the response whenever the TargetEndpoint encounters an HTTP response code of 400 or 500.

Fault rule processing

Any number of fault rules can be defined on ProxyEndpoints and TargetEndpoints. When an error occurs, only the last fault rule whose condition evaluates to true is enforced. Fault rules are evaluated in the following order:

Request Path:

  1. Fault in ProxyRequest: fault rules defined at ProxyEndpoint execute
  2. Fault in Routing: fault rule defined at ProxyEndpoint execute
  3. Fault in TargetRequest: fault rules defined at TargetEndpoint execute
  4. Fault in outbound request to target URL: fault rules defined at TargetEndpoint execute

Response Path:

  1. Fault in TargetResponse: fault rules defined at TargetEndpoint execute
  2. Fault in ProxyResponse: fault rules defined at ProxyEndpoint execute
  3. Fault in returning response to ProxyEndpoint: fault rules defined at ProxyEndpoint execute

Policy attachments in a fault rule are enforced in the order in which the Steps are attached to the fault rule.

To enable fault handling for an API proxy, fault handlers must be configured to identify and categorize predefined exception conditions, in turn enabling API Services to execute policies that manage the exception.

Fault taxonomy

API Services organizes faults into the following categories and subcategories.

Category Subcategory Fault Name Description
Messaging Failures that occur during the message flow (not including policy failures)
  Custom faults {fault_name} Any faults explicitly handled by the API proxy using the Raise Fault policy
Response codes InternalServerError, NotFound HTTP error codes 5xx, 4xx
Routing failures NoRoutesMatched Failure in selecting a named TargetEndpoint for a request
Classification failures NotFound Failures caused by a request URI that does not match any BasePath for any ProxyEndpoint configurations (that is, no API proxies match the URL in the client app's request)
Transport HTTP transport-level errors
  Connectivity ConnectionRefused, ConnectionReset, ConnectionTimeout Failures occur while establishing network or transport-level connections
Request validations ContentLengthMissing, HostHeaderMissing Faults occur during semantics checks on every request
Response validations Faults occur during semantics checks on every response
IO errors SSLHandshakeError, ReadTimeout, ReadError, WriteTimeout, WriteError, ChunkError Read/write errors at client or target endpoints, timeouts, SSL errors, and chunked errors
System Undefined runtime errors
  Memory OutOfMemory, GCOverLimit Memory-related failures
Thread RogueTaskTerminated Failures such as termination of run-away tasks
Step Faults for each Step (Policy) type are defined in the Policy Reference. See Policy reference overview.

An error is always accompanied by a text description of the reason for the failure. When the system raises a fault, a set of attributes are populated to assist in troubleshooting. A fault includes the following information:

  • Reason
  • User-defined custom attributes

 

Help or comments?