Decide what the user sees inside the orchestration
An Extend page can only show the user what the orchestration hands back. A failure the orchestration doesn't handle reaches the page only as a non-2xx response, with no message you wrote. So the orchestration has to catch its own failures and finish with a response body that contains a message written for a person.
Workday's error-handling documentation sets one constraint that shapes this: an error handler can't read the exception message of the step that failed. It starts with the same data the step started with, plus a processingError output that gives the error's location. The message the user reads is therefore one you write, chosen by which step failed, not a technical error passed through.
Building the orchestration side
Use the Synchronous Orchestration template for anything a page waits on. Its Orchestration End step returns a body to the caller. Then:
- Attach a local error handler to each step or group of steps that can fail for a business reason, such as the Workday API request that creates the record. Choose Conditional Outputs. The handler then outputs
isSuccess, which is true when the step succeeded and false when the handler ran instead. - Branch on
isSuccess. Downstream steps must read the failed step's outputs only on the success branch; reading them on the failure branch rethrows the error. - On the failure branch, set a message: build a JSON body with Create Text Template set to
application/json, or with Create JSON. On the success branch, build the same shape withsuccessset to true. - Return that body from Orchestration End.
{ "success": false, "message": "This cost center is closed for new equipment requests. Choose another cost center." }
You can't use Conditional Outputs on a handler attached to the last step of an orchestration or of a group. Put the step that can fail earlier, or wrap the work in a group with steps after it.
For input checks, the Validate component evaluates Boolean conditions with a severity and a message for each. Its outputs are allValid, anyError, anyWarning, and failedValidations, an iterator over each failure's name, severity and summary. Loop over failedValidations to build the message list for the user. A failed validation doesn't stop the orchestration on its own, so branch on anyError before doing any work.
Log the technical detail separately with a Log step, so the run's logs keep what the user message leaves out. Logging in Orchestrate covers what to log.
Showing it next to the field: a deferred endpoint and setError
When the user should fix something before submitting, call the orchestration from the page as a deferred POST endpoint and turn its message into a widget error. That blocks submission until the user corrects the value. Workday documents exactly this shape for a validation endpoint invoked from onChange. Workday's sample apps launch an orchestration through an AMD data provider whose base URL is {{apiGatewayEndpoint}}/orchestrate/v1/apps/{{site.applicationId}}/orchestrations/, with the endpoint URL <orchestrationName>/launch:
{
"name": "checkCostCenter",
"baseUrlType": "workday-orchestrate",
"url": "checkCostCenter/launch",
"httpMethod": "POST",
"authType": "sso",
"deferred": true,
"onSend": "<% { 'costCenterId': costCenter.value[0] } %>"
}
"onChange": "<%
if (!empty self.value) {
var result = checkCostCenter.invoke();
if (!result.success) { self.setError(result.message); }
else { self.clearError(); }
}
%>"
The clearError branch matters. Without it, the error stays after the user picks a valid cost center and the page can't be resubmitted. Extend onSubmit and onChange validation explains why.
Showing it after submit: a result page
When the orchestration does the work itself on submit, launch it as an outbound endpoint. Outbound endpoints submit in the order they appear, so an outboundVariable placed after it can carry its response to the next page of a flow. Workday's Sales Commission sample app uses this shape, reading launchOrchestration.success into a flow variable:
"outboundData": {
"outboundEndPoints": [
{
"name": "submitRequest",
"baseUrlType": "workday-orchestrate",
"url": "submitEquipmentRequest/launch",
"httpMethod": "POST",
"authType": "sso"
},
{
"type": "outboundVariable",
"name": "requestResult",
"variableScope": "flow",
"values": [
{ "outboundPath": "success", "value": "<% submitRequest.success %>" },
{ "outboundPath": "message", "value": "<% submitRequest.message %>" }
]
}
]
}
The flow's next step is a view page that shows flowVariables.message, worded for success or failure. The response field path depends on what your Orchestration End returns, so check it against a real run before you bind it. Read flowVariables defensively (flowVariables.message ?? ''), as Workday's best practices advise.
When the orchestration fails without handling it
Some failures will still escape, such as an unexpected error or a step you didn't wrap. The page then sees a non-2xx response. Two mechanisms control what the user sees.
responseErrorDetail maps an error response to a message. For outbound endpoints there's one responseErrorDetail for the whole outboundData, with errorSummary (a string binding) and errors (a list binding). Workday's default list of failure codes is 301, 302, 303, 307, 401, 404, 407, 408, 500 and 503. To treat any other code as an error, such as 400 or 403, add it to failOnStatusCodes on that endpoint. For inbound endpoints, each endpoint has its own responseErrorDetail and only errorSummary is supported. The bindings read fields of the response body, so they need a body shape you know. Look at a real failed run's response before binding errorSummary to a field.
Custom error pages map the default failure codes to a page of your own through errorPageConfigurations in the SMD. The page receives errorCode and errorMessage. A custom error page overrides responseErrorDetail, and it can't catch errors from deferred inbound endpoints. Use one for "something went wrong, here's who to contact", not for messages the user can act on.
Timeouts are a different failure
A page waits at most 24 seconds for any one endpoint and 60 seconds for the whole request, and a synchronous orchestration triggered by a presentation page gets 25 seconds of total processing time, which overrides any timeout set on the orchestration (Reference: Orchestration Runtime Limits). The 5-minute synchronous limit applies to other callers, not to a page. If the page times out, the work may still have been done. Workday disables the Submit button after a timeout to prevent duplicates. Don't encourage a retry: tell the user to check the record, and move anything that can run past 25 seconds to an asynchronous orchestration, as Workday recommends, and have it report its result somewhere the user can see it later.
Trigger each failure on purpose
Look at the page each time, not only the run.
- Submit a value the orchestration should reject. The page should show your message, either on the field or on the result page, and nothing should be created. Check the target record.
- Correct the value. The error should clear and the submit should succeed, with the success message and the created record.
- Force an unhandled failure in a sandbox, for example by pointing a step at a record that doesn't exist. The page should show your
responseErrorDetailor custom error page, not a raw error. - Open the orchestration's run on the Workday Developer Site. The failed step and your Log entry should explain what the user message doesn't. Workday Orchestrate errors covers reading a run.