Policy Fault Handling

Not applicable

I can't seem to find anything in the Apigee documentation about the "fault" variable which gets populated when a policy raises a fault (eg. Access Token expired). There are several references to "fault.name" which will give you the generic name of the policy that caused the fault (eg. RaiseFault) but you can't specifically catch which policy raised the error.

Up until now I have resorted to workarounds - usually a combination of fault.name and reading status codes but now I need to return a different error depending on the exact cause of a policy failure. Conveniently, this exact cause is well documented under policy Error Code sections. Unfortunately, I can't extract this error code without first entering one of the fault rules and calling an Extract Variables or Javascript policy - not ideal as I want to be able to execute a fault rule depending on the error code.

Setting "continueOnError" to true doesn't seem to set any specific flow variables or error codes (just an XXX.failed) so I can't extract the error prior to entering Error flow.

Is there a solution for this? Some sort of undocumented "fault.errorcode" variable?

1 11 3,214
11 REPLIES 11

sunandita_dam
Participant V

@Edward Unable to understand issue here. 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 and attach appropriate policy. What do you mean by "There are several references to "fault.name" which will give you the generic name of the policy that caused the fault"

0 3 6

You're right...I must've been overthinking things. As a follow up question though, is there any way to find out the exact name of the policy that raised the error?

0 2 6

sunandita_dam

@Edward I don't think its supported out of the box. Someone should confirm. Why do you need to know policy name as well? How will it help?

0 1 6

Off the top of my head, if I have multiple service callouts, I may want to know exactly which one failed. Basically anywhere where identical errors could arise from different error points.

0 0 6

Not applicable

Affirming the comments above - the policy name is not exposed as a flow variable. The fault.name contains descriptive information on the fault that is raised, not necessarily the policy that raised the fault. If you truly need to know the step that caused the fault, then you will need to assign a flow variable prior to the potential fault raising step that identifies the "phase" or "step" about to execute. This can be quite cumbersome to maintain and is not recommended unless absolutely required.

1 0 6

kurtkanaskie
Staff

@Edward Glad I'm not the only one struggling to come up with a clean and manageable solution to this, I would like to differentiate among multiple JavaScript, ServiceCallout, and conditional RaiseFaults policies.

I discovered a pattern that works by checking for the explicit "policy-name" that failed. I haven't tested it for all policy types nor do I have a comprehensive list of the "policy-type" values. Perhaps that should be added to the Error Code Reference page.

User an "outer" condition to catch the "fault.name" and then use an "inner" condition to differentiate by checking for the "policy-name".faile = true.

{policy-type}.{policy-name}.failed = true

For RaiseFault differentiation, you can check

raisefault.{policy-name}.failed

Then in your FaultRules section use this outer condition and inner conditions:

<FaultRule name="raise-faults">
    <Condition>(fault.name = "RaiseFault")</Condition>
    <Step>
        <Condition>(raisefault.RF-missing-required-params.failed = true)</Condition>
        <Name>AM-missing-required-params</Name>
    </Step>
    <Step>
        <Condition>(raisefault.RF-invalid-hmac.failed = true)</Condition>
        <Name>AM-invalid-hmac</Name>
    </Step>
    <Step>
        <Condition>(raisefault.RF-path-suffix-not-found.failed = true)</Condition>
        <Name>AM-resource-not-found</Name>
    </Step>
</FaultRule>

For JavaScript differentiation, you can check

javascript.{policy-name}.failed

Then in your FaultRules section use this outer condition and inner conditions:

<FaultRule name="script-error">
    <Condition>(fault.name = "ScriptExecutionFailed")</Condition>
    <Step>
        <Condition>(javascript.JS-verify-hmac.failed = true)</Condition>
        <Name>AM-Set-Script-Execution-Error-Variables</Name>
    </Step>
    <Step>
        <Condition>(javascript.JS-log.failed = true)</Condition>
        <Name>AM-Set-Script-Execution-Error-Variables</Name>
    </Step>
</FaultRule>

For ServiceCallout differentiation, you can use:

servicecallout.{policy-name}.failed

Then in your FaultRules section use this outer condition and inner conditions:

<FaultRule name="service-callout-error">
    <Condition>(fault.name = "ExecutionFailed")</Condition>
    <Step>
        <Condition>(servicecallout.SC-Get-OAuth-Token.failed = true)</Condition>
        <Name>AM-Set-SC-Execution-Get-OAuth-Variables</Name>
     </Step>
     <Step>
        <Condition>(servicecallout.SC-Get-Refresh-Token.failed = true)</Condition>
        <Name>AM-Set-SC-Execution-Get-Refresh-Variables</Name>
     </Step>
</FaultRule>


The problem with this approach is how to catch remaining "policy-type" errors that don't match the inner conditions. A Step with no condition will always execute and checking the opposite conditions is combersome. See below for a more managable approach.

0 0 6

kurtkanaskie
Staff

The problem with the above approach, is that once the outer condition matches, no other fault rules "outer" conditions will be matched and it is cumbersome to determine the unmatched condition.

So, rather than use and outer condition to match the fault type and an inner condition to match the specific, using a FaultRule with only outer conditions provides easier management of un-matched conditions, as would be the case if you forgot to add a specific condition.

Consider the following approach:

    <!-- RAISE FAULTS SECTION -->
    <FaultRule name="Raise-fault-not-specific">
	<!-- DEFAULT or UNMATCHED RASIE FAULT -->
        <Condition>(fault.name = "RaiseFault")</Condition>
        <Step>
            <Name>AM-default-raise-fault</Name>
        </Step>
    </FaultRule>

    <FaultRule name="Raise-fault-required-params">
        <Condition>(fault.name = "RaiseFault") and (raisefault.RF-missing-required-params.failed = true)</Condition>
        <Step>
            <Name>AM-missing-required-params</Name>
        </Step>
    </FaultRule>

    <FaultRule name="Raise-fault-invalid-hmac">
        <Condition>(fault.name = "RaiseFault") and (raisefault.RF-invalid-hmac.failed = true)</Condition>
        <Step>
            <Name>AM-invalid-hmac</Name>
        </Step>
    </FaultRule>

    <FaultRule name="Raise-fault-suffix-not-found">
        <Condition>(fault.name = "RaiseFault") and (raisefault.RF-path-suffix-not-found.failed = true)</Condition>
        <Step>
            <Name>AM-resource-not-found</Name>
        </Step>
    </FaultRule>

This allows you to differentiate among all RaiseFaults and to catch any unmatched specific RaiseFault conditions using the "AM-default-raise-fault" at the top, which also demonstrates that FaultRule conditions are evaluated from bottom-to-top."

The use of Assign Message in the steps is to set variables for subsequent use in the DefaultFaultRule as described here: https://community.apigee.com/content/kbentry/23724/an-error-handling-pattern-for-apigee-proxies.html

0 2 6

kurtkanaskie

Just to clarify, fault rules in the proxy endpoint are evaluated bottom-to-top BUT, fault rules in the target endpoint are evaluated top-to-bottom AND the *first* one that matches is executed.

See this dicussion: https://community.apigee.com/questions/27639/fault-rule-conditional-policies-failing-to-execute.html...

0 0 6

soujanyaedunuri

@Kurt Kanaskie In the first approach you provided, if we define first step without inner condition, would it not assign generic response message and subsequent step could overwrite if the error matches the inner condition of the step as below?

<FaultRulename="service-callout-error">
<Condition>(fault.name = "ExecutionFailed")</Condition>
	<Step>
		<Name>AM-Set-Generic-Variables </Name>
	</Step>
	<Step>
		<Condition>(servicecallout.SC-Get-OAuth-Toke			n.failed = true)</Condition>
		<Name>AM-Set-SC-Execution-Get-OAuth-Variables		</Name>
	</Step>
	<Step>
		<Condition>(servicecallout.SC-Get-Refresh-Tok		en.failed = true)</Condition>
		<Name>AM-Set-SC-Execution-Get-Refresh-Variabl		es</Name>
	</Step>
</FaultRule>
0 0 6

davissean
Staff
@Kurt Kanaskie @Edward

Error handling shouldn't be this hard. Check out this post for a really clean pattern for error handling: https://community.apigee.com/articles/23724/an-error-handling-pattern-for-apigee-proxies.html

I have used it on four or five projects, and it really makes it easier to define your error types, content and presentation.

1 1 6

kurtkanaskie

Hi @Edward, I use that pattern as well, I was just pointing out a means by which you can differentiate among a fault.name (e.g. RaiseFault) to set specific variables via the AssignMessage.

0 0 6
Top Labels in this Space
Top Solution Authors