What a Workday Extend page actually is

A Workday Extend page is defined by a PMD (Presentation Model Definition) component. Workday's own Extend App Components Reference groups PMDs, along with app preview, under a "Pages" section, so "page" and "PMD" describe the same file. The PMD lists widgets, the endpoints those widgets read or write, and the bindings that connect a widget to a field in an endpoint's response.

An endpoint's host comes from a separate file: the AMD (App Metadata Document) declares a dataProviders entry whose key the PMD's endpoint references as baseUrlType. A page error is almost always a break in one of three places: the endpoint call itself, a binding that expects a value the endpoint never returned, or a script that touches a field before checking it exists. Read the message, then find which of the three it actually names before changing anything.

The endpoint returns nothing, or a 403

An inbound or outbound endpoint calling a Workday REST API needs four things on the PMD side — name, baseUrlType, url, and authType — plus a matching dataProviders entry on the AMD supplying the real host for that baseUrlType:

{ "key": "workday-common", "value": "<% apiGatewayEndpoint + '/common/v1/' %>" }

A blank widget with no visible error usually means the call never reached Workday, or reached it and was rejected silently. Workday secures every REST method with a security domain or business process security policy, and a signed-in user or the app's own system user needs the matching Report/Task permission. A 403 from that check does not automatically become a page error: by default, Presentation Components only route 301, 302, 303, 307, 401, 404, 407, 408, 500 and 503 to a custom error page. 403 is not on that list, so a security rejection can render as an empty widget instead of a message. To make it visible, opt that endpoint's own 403 into failOnStatusCodes:

{
  "name": "worker",
  "baseUrlType": "workday-common",
  "url": "workers/me",
  "authType": "sso",
  "failOnStatusCodes": [{ "code": 403 }]
}

Mapping the code under the site's errorPageConfigurations alone does nothing; the endpoint has to name the code before Workday will route it anywhere.

Bindings to a value that isn't there

A widget's value or valueOutBinding points at a JSON path in an endpoint's response:

"value": "<% worker.data.descriptor %>"

This fails quietly when the field is optional and the current record simply doesn't have it — a worker with no manager, a request with no attachment — rather than when the endpoint itself is broken. Confirm what the endpoint actually returned for that record before assuming the binding path is wrong; a field that exists for one test record and not another is a data condition to design for, not a syntax bug to chase.

Script errors: reading a field that isn't there

PMD Scripting reads like JavaScript but is its own language, so test for absence the way Workday's examples do: call .isEmpty() on the value, and negate it with ! when you want the present case. A field that is missing on some records needs the check before the read, not after:

<%
  if (!worker.data.manager.isEmpty())
    worker.data.manager.descriptor
  else
    'Unassigned'
%>

When a script error names a line, reproduce it with the record that failed. A script that works for one test worker and fails for another is almost always reading an optional field without this check.

The page doesn't show up in the tenant

When a page that validates and builds still isn't reachable for a user, the cause is usually outside the PMD. Check, in order: the app was actually deployed to the tenant being tested (a successful build is not the same event as a deploy); the task or route that opens the page is assigned to the user's security group; and any security domain or business process policy the page's own endpoints depend on is active, not left as a pending policy change. A page that opens for one role and not another is almost always a security-group gap, not a PMD defect — compare the working and failing role's group membership before touching the page source.

Preview behaves differently than the deployed page

App Preview is fast for checking layout and page logic, and it can run against mock endpoint responses without touching a tenant. Workday documents that preview does not behave identically to a deployed app in every respect — including security and timezone handling — so a page that looks right in preview can still fail once deployed, and the reverse also happens. Treat a preview pass as evidence about layout and script logic only; confirm security-dependent and timezone-dependent behavior against a deployed Development, Implementation or Sandbox app.

Prove the fix at the layer that failed

Reproduce the exact finding, change the smallest thing that removes it, and recheck the same layer — an endpoint fix needs a live call to prove it, a security fix needs the actual role to reopen the page, watched in a real browser rather than trusted from a green build alone. For component-level rejections, use the validation-error guide; for full journey proof, use the testing guide. Flow and orchestration failures reached from a page belong in the Orchestrate errors guide. kiweely carries an Extend app through this loop end to end; see /extend.

Sources checked