Handling faults

This pageapplies toApigee andApigee hybrid.

View Apigee Edge documentation.

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.

When an error occurs after a client app calls an API proxy, an error message gets returned to the client. By default, the client receives an often cryptic error message with no details or guidance. But if you want to replace default error messages with more useful custom messages, and even enrich them with things like additional HTTP headers, you need to set up custom fault handling in Apigee.

Custom fault handling also lets you add functionality such as message logging whenever an error occurs.

Tip: Fault handling is a major architectural design task for API proxy development. It's important to take the time to figure out how and when you're going to handle errors, determine what error messages will say, and design error message formats. After (or as) you figure those things out, then use this topic to help you implement your own custom fault handling.

Before we talk about implementing custom error handling in your API proxies, it's helpful to understand how errors occur and how API proxies react to them.

Videos

Note: The following videos were recorded with a previous version of the Apigee UI; however, the concepts are still valid.

Watch the following videos to learn more about fault handling.

VideoDescription
Introduction to fault handling and error flowsLearn about fault handling and what happens when an error occurs in an API proxy.
Handle faults using fault rulesLearn how to handle faults using fault rules.
Raise custom faults using the RaiseFault policyRaise custom faults during API runtime using RaiseFault policy.
Define fault rules in API proxy and target endpointsDefine fault rules in the API proxy and target endpoints and understand the differences.
Understand execution order of fault rulesUnderstand the execution order of fault rules in the API proxy and target endpoints.
Define default fault ruleDefine default fault rule to handle generic errors in your API.

How errors occur

First we'll simply coverhow errors occur. Knowing how errors occur helps you plan for the different situations in which you want to implement custom error handling.

Automatic errors

An API proxy throws an error automatically in the following situations:

For more information on these errors, seeFault taxonomy in this topic.

Custom errors

For situations where there's not an automatic error, you may want to throw a custom error; for example, if a response contains the wordunavailable, or if the HTTP status code is greater than201. Do this by adding aRaiseFault policy to the appropriate place in an API proxy flow.

You can add a RaiseFault policy to an API proxy flow the same as you do any other policy. In the following proxy configuration example, theRaise-Fault-1 policy is attached to the TargetEndpoint response. If the wordunavailable is present in the response from the target service, the RaiseFault policy gets executed and throws an error.

<TargetEndpoint name="default">...  <Response>    <Step>      <Name>Raise-Fault-1</Name>      <Condition>message.content Like "*unavailable*"</Condition>    </Step>  </Response>

This is just to show you that you can throw custom errors. We go into more detail about the RaiseFault policy in theFaultRules vs. the RaiseFault policy section.

For more examples, see theseApigee Community posts:

What API proxies do when errors occur

Here's what happens when a proxy throws an error.

Exit the proxy pipeline

When an API proxy encounters an error, regardless of how it occurs, it exits thenormal flow pipeline, enters an error state, and returns an error message to the client app. Once the API proxy enters the error state, it cannot return processing back to the normal flow pipeline.

For example, assume an API proxy has policies in the following order in the ProxyEndpoint request:

  1. Verify API Key
  2. Quota
  3. JSON to XML

If an error occurs during API key verification, the API proxy moves into an error state. The Quota and JSON to XML policies are not executed, the proxy doesn't proceed to the TargetEndpoint, and an error message is returned to the client app.

Check for FaultRules

In the error state, API proxies also check for the presence of the following (in order) in the API proxy configuration before returning a default error message to the client app:

  1. A<FaultRules> section, which contains the logic to trigger custom error messages (and other policies) based on specific conditions that you define.
  2. A<DefaultFaultRule> section, which triggers a default error message in the following situations:
    • No<FaultRules> are defined.
    • No existing<FaultRules> get executed.
    • The<AlwaysEnforce> element is set to true.

In essence, the API proxy is giving you the opportunity to return a custom error message and trigger other logic. If the proxy finds neither of those sections, or they exist but no custom fault was triggered, the proxy sends its own Apigee-generated default message.

Simple fault handling example

Sample:Learn by doing!
If you want to see a simple fault handling example in action, check out this
Learn by doing example in the Apigee GitHub samples. Just clone the repository and follow the instructions in that topic. You can always come back to this section for more details on how simple fault handling is implemented.

Let's start with a simple example, where a call to an API proxy doesn't contain a required API key. By default, following is the response that gets returned to the client app:

HTTP/1.1401UnauthorizedDate:Wed, 20 Jul 2016 19:19:32 GMTContent-Type:application/jsonContent-Length:150Connection:keep-aliveServer:Apigee Router*Connection#0tohostmyorg-test.apigee.netleftintact{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}

Your API users may be able to figure out the error message, but they may not. And many default errors are more subtle and harder to decipher.

As an API developer, it's up to you to change this message to meet the needs of whoever will ultimately receive the error message, whether it's an iOS app developer or an internal testing group that has its own error message format requirements.

Here's a basic example of how you'd create a custom error message to handle this error. This requires 1) a policy that defines the custom message, and 2) a FaultRule that executes the policy when the proxy goes into an error state.

1. Create a policy that defines the custom message

First, create a policy that defines the custom error message. You can use any type of policy, such as anAssignMessage policy, that can set a payload and optional HTTP headers such as the status code. TheAssignMessage policy is ideal for this. It lets you control message payload, set a different HTTP status code and add HTTP headers.

You don't need to attach the policy to a flow; just create it, as described inCreate the policy.

Following is an exampleAssignMessage policy that:

  • Returns a JSON message.
  • Sets an HTTP status code (911, which is an obvious non-existent status code simply to illustrate the flexibility you have). The status code appears in the HTTP header.
  • Creates and populates a new HTTP header calledinvalidKey.
<AssignMessageasync="false"continueOnError="false"enabled="true"name="invalid-key-message"><DisplayName>Invalidkeymessage</DisplayName><Set><PayloadcontentType="application/json">{"Citizen":"Where's your API key? I don't see it as a query parameter"}</Payload><StatusCode>911</StatusCode></Set><Add><Headers><Headername="invalidKey">InvalidAPIkey!</Header></Headers></Add><IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables><AssignTocreateNew="false"transport="http"type="request"/></AssignMessage>

When this policy is executed, the response to the client app will look like the following. Compare it to the default response shown earlier.

HTTP/1.1911Rejected by API Key Emergency ServicesDate:Wed, 20 Jul 2016 18:42:36 GMTContent-Type:application/jsonContent-Length:35Connection:keep-aliveinvalidKey:Invalid API key!Server:Apigee Router*Connection#0tohostmyorg-test.apigee.netleftintact{"Citizen":"Where's your API key? I don't see it as a query parameter."}

Yes, it's a little silly, but it shows you what's possible. At least now the developer receiving the message knows they forgot to include an API key as a query parameter.

But how does this policy get executed? The next section shows you.

2. Create the <FaultRule> that will trigger the policy

In the<ProxyEndpoint> or<TargetEndpoint> sections of the proxy configuration, you'll add a<FaultRules> XML block that contains one or more individual<FaultRule> sections. Each FaultRule represents a different error you want to handle. In this simple example, we'll use only one FaultRule to show you what it's composed of.

You should also add a<DefaultFaultRule> to provide a custom general error message if none of your FaultRules is executed.

Example

<ProxyEndpoint name="default">...    <FaultRules>       <FaultRule name="invalid_key_rule">            <Step>                <Name>invalid-key-message</Name>            </Step><Condition>(fault.name = "FailedToResolveAPIKey")</Condition>        </FaultRule>    </FaultRules>    <DefaultFaultRule name="default-fault">        <Step>            <Name>Default-message</Name>        </Step>    </DefaultFaultRule>

Key points:

  • The FaultRules are defined in the ProxyEndpoint. This is important. More on putting FaultRules in the ProxyEndpoint vs. TargetEndpoint later.
  • <Name>: The name of the policy to execute. The name comes from the policy'sname attribute on the parent element, as shown in the policy example earlier.
  • <Condition>: Apigee evaluates the condition and executes the policy only if the condition is true. If there are multiple FaultRules that evaluate to true, Apigee executes the first one that is true. (Important: The order in which the FaultRules are evaluated, top to bottom or bottom to top, differs between the TargetEndpoint and ProxyEndpoint, as described in theMultiple FaultRules and execution logic section.) If you don't include a condition, the FaultRule is automatically true. But that's not a best practice. Each FaultRule should have its own condition.

    Note: As you'll see later, Steps can have their owninner conditions that determine whether or not a policy gets executed. (More on that in theMultiple FaultRules and execution logic section.) But Step conditions have nothing to do with whether or not a FaultRule gets executed. Apigee looks at only theouter FaultRule conditions to determine which FaultRule gets executed.
  • <DefaultFaultRule>: If no custom FaultRule is executed, the<DefaultFaultRule> is executed, sending a more generic custom message instead of the cryptic default Apigee-generated message. A<DefaultFaultRule> can also have a<Condition>, but in most cases you won't include one, because you want it to execute no matter what as a last resort.

    The DefaultFaultRule is typically used to return a generic error message for any unexpected error. An example would be 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.

Multiple FaultRules and execution logic

Sample:Learn by doing!
If you want to dive in and get your hands dirty with an easy-to-use sample that illustrates multiple FaultRules, check out this
Learn by doing example in the Apigee GitHub samples. Just clone the repository and follow the instructions in that topic. You can always come back to this section to get more details on how it all works.

In theSimple fault handling example section, we used a simple example of a single FaultRule and condition. In a real-world API project, with all the possible errors that can occur, you're likely to have multiple FaultRules and a DefaultFaultRule in both your<ProxyEndpoint> and<TargetEndpoint>. Ultimately, though, only one FaultRule is executed when an API proxy goes into an error state.

This section describes the logic Apigee uses in handling FaultRules, from how it arrives at a single FaultRule to execute to howinner Step conditions are handled when their FaultRule is triggered. This section also provides guidance on when to define FaultRules in the<ProxyEndpoint> vs. the<TargetEndpoint>, and describes the relationship between FaultRules and theRaiseFault policy.

FaultRules execution

Note:Outer andinner conditions

In this topic we refer toouter andinner conditions. You can also think of them asFaultRule andStep conditions. The difference is important. Following is an example of a FaultRule that has an outer FaultRule condition and an inner step condition. We'll discuss the differences in this section.

<FaultRule name="over_quota">            <Step>                <Name>developer-over-quota-fault</Name><!-- Inner (Step) condition. Only gets executed if                     the FaultRule is executed. -->                <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>            </Step>            <!-- Outer (FaultRule) condition. Apigee evaluates this                 to determine whether or not to execute                 the FaultRule. -->            <Condition>(fault.name = "QuotaViolation")</Condition>        </FaultRule>

In brief, here's the logic Apigee uses when an API proxy goes into an error state. Note that there is a slight difference between FaultRules evaluation in the ProxyEndpoint versus the TargetEndpoint.

  1. Apigee evaluates the FaultRules in either the ProxyEndpoint or TargetEndpoint, depending on where the error occurred:
    • ProxyEndpoint - Apigee starts with thebottom<FaultRule> in the configuration XML and works its way up, evaluating the<Condition> of each<FaultRule> (theouter condition, not theinner<Step> conditions).
    • TargetEndpoint - Apigee starts with thetop<FaultRule> in the configuration XML and works its way down, evaluating the<Condition> of each<FaultRule> (theouter condition, not theinner<Step> conditions).
  2. Executes thefirst FaultRule whose condition is true. If a FaultRule has no condition, it's true by default.
  3. If no FaultRule is executed, Apigee executes the<DefaultFaultRule>, if present.

Following are examples with inline comments.

ProxyEndpoint execution

Evaluation of ProxyEndpoint FaultRules is bottom to top, so start reading at the last FaultRule in the following sample and work your way up. Look at the DefaultFaultRule last.

<ProxyEndpoint name="default">...    <FaultRules><!-- 3. This FaultRule is automatically TRUE, because there's noouter     condition. But because the FaultRule just below this got     executed (bottom-to-top evaluation in a ProxyEndpoint), Apigee     doesn't even evaluate this FaultRule.     Note that it's not a best practice to have a FaultRule without     an outer condition, which automatically makes the FaultRule true. -->        <FaultRule name="random-error-message">            <Step>                <Name>Random-fault</Name>            </Step>        </FaultRule><!-- 2. Let's say this fault is TRUE. TheQuota policy threw a QuotaViolation     error. This is the first FaultRule to be TRUE, so it's executed.     Now the Steps are evaluated, and for the ones whose conditions     evaluate to TRUE, their policies are executed. Steps without     conditions are automatically true. --><FaultRule name="over_quota">            <Step>                <Name>developer-over-quota-fault</Name>                <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>            </Step>            <Step>                <Name>global-over-quota-fault</Name>                <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>            </Step>            <Step>                <Name>log-error-message</Name>            </Step>            <Condition>(fault.name = "QuotaViolation")</Condition>        </FaultRule><!-- 1. Because this is the ProxyEndpoint, Apigee looks at this FaultRule     first. But let's say this FaultRule is FALSE. A policy did not     throw a FailedToResolveAPIKey error. Apigee moves UP to check     the next FaultRule. -->        <FaultRule name="invalid_key_rule">            <Step>                <Name>invalid-key-message</Name>            </Step>            <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>        </FaultRule>    </FaultRules><!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed.     If a FaultRule is executed, but none of its Steps are executed,     The DefaultFaultRule is not executed (because Apigee has already     executed its one FaultRule). -->    <DefaultFaultRule name="default-fault">        <Step>            <Name>Default-message</Name>        </Step>    </DefaultFaultRule>

TargetEndpoint execution

Evaluation of TargetEndpoint FaultRules is top to bottom, so start reading at the first FaultRule in the following sample and work your way down. Look at the DefaultFaultRule last.

<TargetEndpoint name="default">...    <FaultRules><!-- 1. Because this is the TargetEndpoint, Apigee looks at this FaultRule     first. Let's say this FaultRule is FALSE.     A policy did not throw a FailedToResolveAPIKey error.     Apigee moves down to the next FaultRule. -->        <FaultRule name="invalid_key_rule">            <Step>                <Name>invalid-key-message</Name>            </Step>            <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>        </FaultRule><!-- 2. Let's say this fault is TRUE. TheQuota policy threw a QuotaViolation     error. This is the first FaultRule to be TRUE, so it's executed.     Now the Steps are evaluated, and for the ones whose conditions     evaluate to TRUE, their policies are executed. Steps without     conditions are automatically true. -->        <FaultRule name="over_quota">            <Step>                <Name>developer-over-quota-fault</Name>                <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>            </Step>            <Step>                <Name>global-over-quota-fault</Name>                <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>            </Step>            <Step>                <Name>log-error-message</Name>            </Step>            <Condition>(fault.name = "QuotaViolation")</Condition>        </FaultRule><!-- 3. This FaultRule is automatically TRUE, because there's noouter     condition. But because the FaultRule just above this got     executed (top-to-bottom evaluation in a TargetEndpoint), Apigee     doesn't even evaluate this FaultRule.     Note that it's not a best practice to have a FaultRule without     an outer condition, which automatically makes the FaultRule true. -->        <FaultRule name="random-error-message">            <Step>                <Name>Random-fault</Name>            </Step>        </FaultRule>    </FaultRules><!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed.     If a FaultRule is executed, but none of its Steps are executed,     The DefaultFaultRule is not executed (because Apigee has already     executed its one FaultRule). -->    <DefaultFaultRule name="default-fault">        <Step>            <Name>Default-message</Name>        </Step>    </DefaultFaultRule>

Fault rule order

As you can see in the previous example, the order in which you put your FaultRules is important depending on whether the error occurs in the ProxyEndpoint versus the TargetEndpoint.

For example:

ProxyEndpoint orderTargetEndpoint order

In the following example, since evaluation is bottom to top, FaultRule 3 is executed, which means FaultRules 2 and 1 aren't evaluated.

5. FaultRule 1: FALSE

4. FaultRule 2: TRUE

3. FaultRule 3: TRUE

2. FaultRule 4: FALSE

1. FaultRule 5: FALSE

In the following example, since evaluation is top to bottom, FaultRule 2 is executed, which means FaultRules 3, 4, and 5 aren't evaluated.

1. FaultRule 1: FALSE

2. FaultRule 2: TRUE

3. FaultRule 3: TRUE

4. FaultRule 4: FALSE

5. FaultRule 5: FALSE

Policies to include

You can execute any policies from a FaultRule by putting them in Steps. For example, you can execute anAssignMessage policy to format a response to the client app, then log a message with theMessageLogging policy. Policies are executed in the order you put them (top to bottom in the XML).

Fault rules are triggered ONLY in an error state (about continueOnError)

The heading may seem like we're repeating ourselves, but there's one particular nuance to be aware of with regard to a proxy error causing an API proxy to enter an error state—or rather,not entering an error state: thecontinueOnError attribute on a policy.

To recap: An API proxy evaluates<FaultRules> and<DefaultFaultRule>only if the proxy has entered an error state. That means that even if a FaultRule condition evaluates to true, it won't get triggered if the proxy isn't in an error state.

However, here's an example of an error occurring and the proxy not entering an error state. On any policy, you can set an attribute on the parent element calledcontinueOnError. That attribute is very important with regard to fault handling, because it determines whether or not the proxy enters an error state if the policy fails. In most cases, you'll want to keep the defaultcontinueOnError="false", which puts the proxy in an error state if the policy fails, and your custom error handling will get triggered. However, ifcontinueOnError="true" (for example, if you don't want the failure of a Service Callout to stop the proxy execution), the proxy willnot go into an error state if that policy fails, and the proxy won't look at your FaultRules.

For information on logging errors whencontinueOnError="true", seeHandling policy faults within the current flow.

Where to define FaultRules: ProxyEndpoint or TargetEndpoint

When an API proxy experiences an error, the error occurs either in the<ProxyEndpoint> (request from or response to client app) or in the<TargetEndpoint> (request to or response from target service). Wherever that error occurs is where Apigee looks for FaultRules.

For example, if a target server isn't available (HTTP status code503), the API proxy would go into an error state in the<TargetEndpoint> response, and the normal API proxy flow wouldn't continue to the<ProxyEndpoint>. If you have FaultRules defined only in the<ProxyEndpoint>, they won't handle that error.

Here's another example. If aRaiseFault policy on the<ProxyEndpoint> response triggers an error, a FaultRule in the<TargetEndpoint> won't get executed.

Note: Remember, as mentioned in theFaultRules execution section, FaultRules are evaluated in the following order. The first FaultRule whoseouter condition evaluates to true is executed.
  • ProxyEndpoint: Bottom up, last FaultRule in the XML configuration first.
  • TargetEndpoint: Top down, first FaultRule in the XML configuration first.

FaultRules vs. the RaiseFault policy

Fault rules and theRaiseFault policy may on the surface sound like alternative ways to accomplish fault handling; and in some ways that's true. But they also work together. This section explains the relationship between the two. Understanding this relationship should help you design your fault handling, especially if you want to use both.

In brief:

  • Fault rules are always evaluated when an API proxy enters an error state.
  • TheRaiseFault policy is a way of putting an API proxy in an error state when an error wouldn't have otherwise occurred.

    For example, if you want to throw an error if the HTTP status code in the response from the target service is greater than200, you add aRaiseFault policy in your response flow. It would look something like this:

    <TargetEndpoint name="default">    <PreFlow name="PreFlow">...        <Response>            <Step>                <Name>Raise-Fault-1</Name><!-- If the condition is true, the Raise-Fault-1 policy gets executed -->                <Condition>(response.status.code GreaterThan "200")</Condition>            </Step>        </Response>

    The RaiseFault policy also sends an error message to the client app.

What happens when a RaiseFault policy triggers an error, which puts the proxy in an error state, which potentially executes a FaultRule? Here's where things can get a little tricky. If the RaiseFault policy returns an error messageand a FaultRule gets triggered and returns an error message, what gets returned to the client app?

  • Since the FaultRule or DefaultFaultRule is executed after the RaiseFault policy, the FaultRule response data wins.
  • The RaiseFault policy response data (status code or message payload) is used if that data is not set by the FaultRule or DefaultFaultRule.
  • If both the RaiseFault policy and FaultRule add custom HTTP headers, both are included in the response. Duplicate header names create a header with multiple values.

Here's an example of what's set by a RaiseFault policy and a FaultRule, and what gets returned to the client app. The samples are designed for brevity, not for best practices.

What's set by a RaiseFault policy and a FaultRule.

Client app receives:

StatusCode:468Payload:{"Whoa":"Sorry."}Header:errorNote:woops,gremlins

<- Fault rules policy sets this:

StatusCode:[none]Payload:{"Whoa":"Sorry."}Header:errorNote:gremlins

<- RaiseFault policy sets this:

Status Code: 468Payload: {"DOH!":"Try again."}Header:  errorNote: woops
Note: If the<DefaultFaultRule> has the child element<AlwaysEnforce>true</AlwaysEnforce>, the DefaultFaultRule is always executed, even if another FaultRule was executed as well. Any payload and/or headers set by a policy in the DefaultFaultRule get returned to the client, since it's the last to execute.

Building conditions

Conditions are the key to FaultRule execution. You create FaultRule conditions the same way you do for other conditions in Apigee, such as for conditional flows or RaiseFault conditions.

To put the rest of this section in context, here's a sample fault rule that has an outer FaultRule condition and an inner Step condition.

<FaultRule name="invalid_key_rule">    <Step>        <Name>invalid-key-message</Name>        <Condition>oauthV2.Verify-API-Key-1.failed = true</Condition>    </Step>    <Condition>fault.name = "FailedToResolveAPIKey"</Condition></FaultRule>

Variables specific to policy errors

Thefault.name and{policy_namespace}.{policy_name}.failed variables are available when a policy throws an error.

fault.name

When a policy fails, catch the error in a condition using thefault.name variable. For example:

<Condition>fault.name = "policy_error_name"</Condition>

The error name appears in the default error message. For example, in the following, the fault name isFailedToResolveAPIKey. In this case, a flow variable calledfault.name is set to the valueFailedToResolveAPIKey.

{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}

So the condition would look like this:

<Condition>fault.name = "FailedToResolveAPIKey"</Condition>

See thePolicy error reference for a list of policy errors.

{policy_namespace}.{policy_name}.failed

The*.failed variable is available when a policy fails. Following are examples of*.failed variables for different policies. For policy namespaces, see the flow variables in eachpolicy reference topic.

Other available variables

When an API proxy goes into an error state, the only available variables for use in conditions are:

  • The variables of the policy that failed.
  • The HTTP message variables that exist at the point of failure. For example, if an error is thrown in the response, a FaultRule in the<TargetEndpoint> could use HTTP dataresponse.status.code,message.content,error.content, and so on. Or if aQuota policy failed, you could use the variableratelimit.{quota_policy_name}.exceed.count. Use theDebug tool and thePolicy reference to help you figure out which variables and HTTP data are available.

More information

Best practices for fault handling

Fault handling is a major architectural design task for API proxy development. It's important to take the time to figure out how and when you're going to handle errors, determine what error messages will say, and design error message formats. After (or as) you figure those things out, then use these best practices to help you with your fault handling implementation.

Here are some best practices in designing and building fault handling:

Pattern for centralized, reusable fault handling

An error-handling pattern for Apigee proxies describes a pattern for centralized fault handling without code duplication.

Creating FaultRules

To add a FaultRule you need to edit the XML configuration of the ProxyEndpoint or TargetEndpoint. You can use the Apigee UI to make this edit in theCode pane of theDevelop view for an API proxy, or edit the XML file that defines the ProxyEndpoint or TargetEndpoint.

If you create FaultRules in the Apigee UI, first create the policies you want to execute, then add them to the FaultRule configuration. (You'll get an error in the UI if you try to save a FaultRule that references a policy that hasn't been created yet.)

Adding policies to a FaultRule

While you can put any policy in the FaultRule, you commonly use theAssignMessage policy to generates a custom response message for an error condition. AssignMessage enables you to configure an HTTP response with payload, HTTP status code, and headers.

Note: A policy used in a FaultRule is typically not used in the normal flow pipeline. Therefore, when using the Apigee UI to create a policy for a FaultRule, select the plus sign,+, next toPolicies in the UI to add the policy:

The Policies bar includes a plus sign and an expander arrow.

The example below shows a typicalAssignMessage policy configuration:

<AssignMessagename="AM-Invalid-Key"><Set><PayloadcontentType="text/plain">Thatisanerror.</Payload><StatusCode>401</StatusCode></Set><IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables></AssignMessage>

Notice that it does not specify an<AssignTo> element. This means it will assign to the ambient message, depending on where the policy is attached.

You can now use this policy in your FaultRule. Notice how you reference the AssignMessage policy by name in the FaultRule:

<ProxyEndpoint name="default">  ...  <FaultRules>    <FaultRule name="invalid_key_rule">      <Step>        <Name>AM-Invalid-Key</Name>      </Step>      <Condition>fault.name = "InvalidApiKey"</Condition>    </FaultRule>  </FaultRules></ProxyEndpoint>

When you deploy the configuration above, the API proxy will execute the AssignMessage policy calledAM-Invalid-Key whenever an app presents an invalid API key.

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

<ProxyEndpoint name="default">  ...  <FaultRules>    <FaultRule name="invalid_key_rule">      <Step>        <Name>AM-Invalid-Key</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 theMessageLogging policy, theExtractVariables policy, theAssignMessage policy, or any other policy in the FaultRule. Note that processing of the FaultRule stops immediately if either of these situations occur:

  • Any policy in the FaultRule causes an error
  • Any of the policies in the FaultRule is of type RaiseFault

Defining the custom error message returned from a FaultRule

As a best practice, you should define clear error responses from your APIs. In that way, you deliver consistent and helpful information to your clients.

The followingAssignMessage policy example uses the<Payload> and<StatusCode> tags to define the custom error response sent back to the client on an InvalidApiKey error (see previous FaultRules example).

<AssignMessagename="AM-Invalid-Key"><Set><PayloadcontentType="text/plain">Youhaveattemptedtoaccessaresourcewithoutthecorrectauthorization.Contactsupportatsupport@mycompany.com.</Payload><StatusCode>401</StatusCode></Set><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.

Creating a DefaultFaultRule

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

For example, the TargetEndpoint configuration below defines a DefaultFaultRule that invokes a policy namedAM-Return-Generic-Error:

<TargetEndpoint name="default">  ...  <FaultRules>    ...  </FaultRules>  <DefaultFaultRule name="fault-rule">    <Step>      <Name>AM-Return-Generic-Error</Name>    </Step>  </DefaultFaultRule>  <HTTPTargetConnection>    <URL>https://mytarget.example.net</URL>  </HTTPTargetConnection></TargetEndpoint>

The DefaultFaultRule 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:

<AssignMessagename="AM-Return-Generic-Error"><Set><Payloadtype="text/plain">SERVICEUNAVAILABLE.PLEASECONTACTSUPPORT:support@company.com.</Payload></Set></AssignMessage>

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

  <DefaultFaultRule name="fault-rule">    <Step>      <Name>AM-Return-Generic-Error</Name>    </Step>    <AlwaysEnforce>true</AlwaysEnforce>  </DefaultFaultRule>

One use of the DefaultFaultRule is to determine the type of error that occurs when you otherwise cannot determine it. For example, if your API proxy is failing due to an error that you cannot determine, you can use the DefaultFaultRule to invoke the following AssignMessage policy. This policy writes thefault.name value to a header namedUnhandled-Fault in the response:

<AssignMessage name="AM-Set-Fault-Header">  <Set>    <Headers>      <Header name="Unhandled-Fault">{fault.name}</Header>    </Headers>  </Set>  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables></AssignMessage>

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

Adding message logging to the PostClientFlow

ThePostClientFlow is the only flow that executes after the proxy enters the error state. Only theMessageLogging policy can be attached to this flow, which is executed after the response is sent back to the client. Although attaching theMessageLogging policy to this flow is technically not error handling, you can use it to log information in the event of an error. Because it is executed regardless of whether the proxy succeeded or failed, you can put Message Logging policies in the PostClientFlow and be guaranteed that they always execute.

Handling policy faults within the current flow

The examples shown so far all use a FaultRule on the ProxyEndpoint or TargetEndpoint to handle any policy errors as part of the error state. That is because the default value of thecontinueOnError element of a policy isfalse, meaning that when an error occurs in a policy, control is directed to the error state. Once in the error state, 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 thecontinueOnError element totrue 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 aVerifyAPIKey policy namedverify-api-key with thecontinueOnError element set totrue:

<VerifyAPIKey continueOnError="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 theVerifyAPIKey policy sets theoauthV2.verify-api-key.failed variable totrue, 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>oauthV2.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 VerifyAPIKey policy, then the policy namedFaultInFlow policy executes. Otherwise, theFaultInFlow policy is skipped. TheFaultInFlow 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 RaiseFault policy

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

One use of the RaiseFault 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 policyFaultInFlow to execute if the condition is met. IfFaultInFlow is a RaiseFault policy, then control transfers to the error state. Or, you might insert a RaiseFault policy in a flow to debug and test your FaultRules.

When a RaiseFault policy triggers an error, you can use the following FaultRule and condition to process it:

<FaultRule name="raisefault_rule">  <Step>    <Name>POLICY-NAME-HERE</Name>  </Step>  <Condition>fault.name = "RaiseFault"</Condition></FaultRule>

Note that the condition tests for a fault namedRaiseFault. The RaiseFault policy always sets the value offault.name toRaiseFault. You can also set custom variables within a RaiseFault policy. If you do that, then you can test those variables within the Condition elements.

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, Apigee treats HTTP response codes in the1xx-3xx range assuccess, and HTTP response codes in the range4xx-5xx asfailure. That means any response from the backend service with an HTTP response code4xx-5xx automatically invokes the error state, 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 range4xx-5xx as "failure" but only5xx, or you might want to return custom error messages for HTTP response codes400 and500.

In the next example, you use thesuccess.codes property to configure the TargetEndpoint to treat HTTP response codes400 and500 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 state:

<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 thesuccess.codes property to a range of values..

Setting thesuccess.codes property overwrites the default values. Therefore, if you want to add HTTP code400 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 code400 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 codes400 and500 to return a customized response message to the requesting app. The following TargetEndpoint uses the policy namedReturnError to handle HTTP400 and500 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 calledReturnError to handle the response whenever the TargetEndpoint encounters an HTTP response code of400 OR500.

Fault taxonomy

API Services organizes faults into the following categories and subcategories.

CategorySubcategoryFault NameDescription
MessagingFailures that occur during the message flow (not including policy failures)
Custom faults{fault_name}Any faults explicitly handled by the API proxy using the RaiseFault policy
Response codesInternalServerError, NotFoundHTTP error codes5xx,4xx
Routing failuresNoRoutesMatchedFailure in selecting a named TargetEndpoint for a request
Classification failuresNotFoundFailures 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)
TransportHTTP transport-level errors
ConnectivityConnectionRefused, ConnectionReset, ConnectionTimeoutFailures occur while establishing network or transport-level connections
Request validationsContentLengthMissing, HostHeaderMissingFaults occur during semantics checks on every request
Response validationsFaults occur during semantics checks on every response
IO errorsSSLHandshakeError, ReadTimeout, ReadError, WriteTimeout, WriteError, ChunkErrorRead/write errors at client or target endpoints, timeouts, TLS/SSL errors, and chunked errors
SystemUndefined runtime errors
MemoryOutOfMemory, GCOverLimitMemory-related failures
ThreadRogueTaskTerminatedFailures such as termination of run-away tasks
PolicyFaults for each policy type are defined in thePolicy reference.

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

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.