Workday Extend enforces two distinct sets of file attachment limits depending on how the file enters
Workday: Model Attachment Objects and the Workday Graph API allow up to 30 MB per file,
whereas the PMD fileUploader widget caps uploads at 10 MB per file (10,485,760 bytes) and
a maximum of 5 files per widget (50 MB total). When you use fileUploader on an Extend
page—even if the page submits to a Graph API mutation or an Attachment Object endpoint—the stricter
10 MB fileUploader limit always overrides the 30 MB API limit.
Beyond file size and count caps, most upload and retrieval failures stem from blocked file
extensions, missing Collection suffixes on Attachment Object URLs, reversed multipart/form-data
part ordering, or missing Accept: application/json headers when reading attachment metadata.
Documented attachment and fileUploader limits
| Component or Layer | Limit Type | Documented Maximum | Notes |
|---|---|---|---|
Component or LayerPMD fileUploader widget | Limit TypeMaximum file size | Documented Maximum10 MB (10,485,760 bytes) | NotesCan be lowered (never raised above 10 MB) on page load via maxFileSize |
Component or LayerPMD fileUploader widget | Limit TypeMaximum files per upload | Documented Maximum5 files (50 MB total) | NotesSet "singular": true to restrict the user to 1 file; minRows cannot exceed 5 |
Component or LayerPMD fileUploader widget | Limit TypeImage auto-resize (maxImageDimension) | Documented Maximum1 to 5,000 pixels (800–2,000 recommended) | NotesResizes longest edge for bmp, gif, jpg, jpeg, png sent to Workday REST APIs |
| Component or LayerModel Attachment Objects | Limit TypeAttachment definitions per app | Documented Maximum5 per app | NotesUp to 5 indexed fields per attachment object (plus auto-indexed SINGLE_INSTANCE fields) |
| Component or LayerModel Attachment Objects | Limit TypeMaximum file size (direct API) | Documented Maximum30 MB | NotesOverridden by the 10 MB fileUploader limit when uploaded from an Extend page |
| Component or LayerWorkday Graph API | Limit TypeMaximum file size | Documented Maximum30 MB | NotesVirus-scanned on upload; downloadID links expire after 1 hour |
| Component or LayerTenant instance storage | Limit TypeTotal Business + Attachment Object instances | Documented Maximum10 million (Extend Core/Legacy) or 100 million (Extend Professional / Extend AI) | NotesShared across all Extend business objects and attachment objects in the tenant; check Extend Object Instance Count report |
Allowed and blocked file types (fileTypes)
By default, if you omit the fileTypes attribute on a fileUploader widget, Workday only permits
six extensions:
doc,docx,html,htm,pdf,txt
To allow additional formats (such as images or spreadsheets), pass a comma-separated list of
extensions ("fileTypes": "pdf,png,jpg,jpeg") or set "fileTypes": "*" to allow all non-blocked
types. You can customize the alert shown on invalid extensions with fileTypesErrorMessage.
Hard-blocked extensions and tenant-level overrides
Even when you set "fileTypes": "*", fileUploader permanently blocks executable and script
extensions:
bas,bat,com,exe,js,lnk,ocx,reg,sct,sys,vb,vbe,vbs,wsc,wsf,wsh
In addition, your tenant's global file-type whitelist governs both fileUploader and the Graph API.
If a file extension is disabled in the Edit Tenant Setup - System task (under File Type Setup
Instructions), uploads of that file type will fail even when listed in fileTypes.
How Model Attachment Objects work
When you create an Attachment Object in your Extend app model, Workday automatically generates four system fields on every instance:
file: Stores the binary file or image as a base64-encoded string.fileName: Writable viaPOSTandPUTrequests.fileLength: Read-only integer derived automatically from the uploaded file's byte size.contentType: Read-only MIME descriptor derived automatically from the uploaded file.
Workday also provides the File Size report field (secured by the Public Reporting Items domain in the Tenant Non-Configurable functional area) so you can inspect attachment disk usage in custom reports or WQL queries.
Single-attachment vs. multi-attachment data modeling
- One attachment per Business Object: Define a
SINGLE_INSTANCEfield on the Business Object that targets the Attachment Object. - Multiple attachments per Business Object: Define a
SINGLE_INSTANCEfield on the Attachment Object itself that targets the parent Business Object. Each uploaded file creates a separate Attachment Object instance referencing the same parent Business Object record.
Configuring fileUploader outbound bindings
The fileUploader widget only supports POST outbound endpoints. The required valueOutBinding
syntax depends on which API receives the upload:
| Target Outbound Endpoint | valueOutBinding Format |
Endpoint url & Metadata Rules |
|---|---|---|
| Target Outbound EndpointModel Attachment Object REST API | valueOutBinding Format<endpointName>:<defaultCollectionName> | Endpoint url & Metadata RulesAppend Collection to the endpoint url (for example, charityLogosCollection). You must specify metadata on fileUploader (use "<% { : } %>" if there are no custom fields). |
| Target Outbound EndpointWorkday Graph API mutation | valueOutBinding Format<endpointName>:<partName> | Endpoint url & Metadata RulesOmit the numeric index in valueOutBinding (use createAttachments:file), then map myFileUploader.rows to 'file' + index in graphQuery.variables. |
| Target Outbound EndpointWorkday REST sub-resource (file only) | valueOutBinding Format<endpointName> | Endpoint url & Metadata RulesFor endpoints like POST /entries/{id}/attachments that take only the binary file, specify just the outbound endpoint name. |
| Target Outbound EndpointWorkday multipart REST API (file + JSON) | valueOutBinding Format<endpointName>:<filePartName> | Endpoint url & Metadata RulesBuild self.data.jsonData in the endpoint's onMultiPartSend script and reference "file": "cid:<filePartName>". |
| Target Outbound EndpointThird-party multipart REST API | valueOutBinding Format<endpointName>:<filePartName> | Endpoint url & Metadata RulesBind JSON fields on other widgets using <endpointName>:<formDataName>:<jsonFieldName> or populate self.data.<formDataName> in onMultiPartSend. |
Uploading to a Model Attachment Object in PMD
When uploading to a Model Attachment Object, always target its collection endpoint by appending
Collection to the defaultCollection name in the outbound endpoint url, and always include the
metadata attribute on fileUploader:
{
"type": "fileUploader",
"id": "receiptUploader",
"label": "Upload Receipts",
"valueOutBinding": "postReceipts:expenseReceipts",
"fileTypes": "pdf,png,jpg,jpeg",
"maxImageDimension": 1200,
"singular": false,
"metadata": "<% { 'uploadedBy': {'id': worker.id} } %>"
}
If your attachment metadata depends on values the user types into other widgets on the same page
(which change after initial page load), modify self.data.metadata.<defaultCollectionName> inside
the outbound endpoint's onMultiPartSend event handler:
{
"name": "postReceipts",
"baseUrlType": "app",
"url": "expenseReceiptsCollection",
"httpMethod": "POST",
"authType": "sso",
"exclude": "<% empty(receiptUploader.children) %>",
"onMultiPartSend": "<%
for (var item : self.data.metadata.expenseReceipts) {
item.fileDescription = descriptionInput.value;
}
self.data;
%>"
}
Uploading and downloading files with the Workday Graph API
To upload files through a Graph API mutation (POST https://api.workday.com/graphql/v1), bind
"valueOutBinding": "createAttachments:file" on fileUploader (without a trailing number) and use
myFileUploader.rows.map((row, index) => ...) in graphQuery.variables to generate zero-indexed
part names (file0, file1) for the File-typed attachmentContent field:
"logos": "<%
myFileUploader.rows.map((row, index) => {
{
'attachmentContent': 'file' + index,
'uploadedBy': graph:createId(worker.id),
'uploadedDate': date:getTodaysDate(date:getDateTimeZone(userTimeZone))
}
});
%>"
To download files via Graph API, query the attachment object's downloadID, descriptor, and
contentType fields. Because Graph API queries cannot return raw binary streams directly, pass the
returned downloadID (which is valid for 1 hour) to the Attachments REST API inside your
fileUploaderRow's attachmentList:
https://api.workday.com/attachments/v1/graphql/<% file.downloadID %>
Troubleshooting common file upload and download errors
1. HTTP 500 Internal Server Error on direct multipart/form-data REST uploads
When calling a Model Attachment Object REST API directly from an orchestration or external client
using multipart/form-data, the order of the form parts is strictly enforced. You must send the
JSON data form part (containing "file": "cid:filedata" and your metadata fields) before the
binary filedata part. Sending the binary file part before the data JSON part causes a 500
Internal Server Error.
2. Uploaded files silently fail to save when using onMultiPartSend
When fileUploader constructs a request for a Model Attachment Object collection endpoint, it
populates each array element in self.data.metadata.<defaultCollectionName> with a
"file": "cid:<defaultCollectionName><index>" reference. If your onMultiPartSend script
overwrites the array elements instead of mutating individual properties on each element—or if
console.info(...) is the last line of the script instead of self.data;—the cid: file
references are lost and Workday does not save the files.
Also, never use valueOutBinding on other page widgets (such as hidden or text widgets) to
write to the same Attachment Object endpoint when metadata is configured on fileUploader.
3. GET on an Attachment Object returns raw binary instead of JSON metadata
Calling GET /apps/{appId}/v1/{attachmentCollection}/{id} without headers returns the raw binary
file content. If you want to read the Attachment Object's metadata fields (fileName, fileLength,
contentType, and custom fields), you must include the HTTP header Accept: application/json.
4. Downloaded Extend attachment has the wrong filename or fails to open
When configuring an attachmentList inside a fileUploaderRow to download a Model Attachment
Object via REST, do not bind attachmentName to the object's descriptor. Always bind
attachmentName to the attachment object's fileName field (for example,
"attachmentName": "<% getData.image.fileName %>"). (By contrast, when querying an attachment via
the Graph API, the Graph schema returns the filename inside descriptor.)
5. Bulk delete (?bulk=true) fails on Attachment Objects
While Custom Business Objects support ?bulk=true on POST, PUT, PATCH, and DELETE, the
DELETE operation on Model Attachment Objects does not support bulk=true. Delete attachment
instances individually by ID using deleteEndPoint.
How kiweely fits
kiweely configures your Model Attachment Objects, generates the matching fileUploader and
attachmentList PMD bindings, and verifies multipart upload and download flows in your real tenant.
In your Workday personal developer account and its tenant, Kiweely Personal is free
(Kiweely Personal is free for your Workday personal developer account and its tenant. Any other tenant needs a Personal licence, $99 a month, or a seat in your firm.).
Frequently asked questions
Can I increase the fileUploader maximum file size above 10 MB?
No. Although Model Attachment Objects and the Workday Graph API support files up to 30 MB when
called directly via API, the PMD fileUploader widget enforces a hard ceiling of 10 MB (10,485,760
bytes) per file and 5 files per widget. The maxFileSize attribute on fileUploader can only
restrict the size to a smaller byte count between 1 and 10485760.
Why does my fileUploader fail when submitting to an empty Attachment Object with no custom fields?
When binding fileUploader to a Model Attachment Object collection endpoint
(<endpoint>:<collection>), the metadata attribute on fileUploader is required even if your
Attachment Object has zero custom metadata fields. Set "metadata": "<% { : } %>" to pass an empty
map so fileUploader generates the required cid: file references.
How long is a Graph API attachment downloadID valid?
Every downloadID returned by a Workday Graph API query expires after 1 hour. Fetch the
downloadID on page load and pass it immediately to
https://api.workday.com/attachments/v1/graphql/{downloadID} in your attachmentList widget rather
than storing downloadID values in long-lived records.
Sources checked
- Workday Extend Developer Guide: Concept, Attachment Objects
- Workday Extend Developer Guide: Concept, fileUploader
- Workday Extend Developer Guide: fileUploader Tag Reference
- Workday Extend Developer Guide: Reference, Limits on Model Components
- Workday Extend Developer Guide: Reference, Limits on Presentation Components
- Workday Extend Developer Guide: Graph API Attachments
- Workday Extend Developer Guide: Upload Files with Graph API
- Workday Extend Developer Guide: Download Files with Graph API