object/exists FormID 20512
HEAD-probe whether an object exists in a bucket — returns a boolean, never downloads the object.
HEAD, not GET: this operation issues an S3
HeadObject call — it confirms presence, size, and metadata without transferring the object body. Use it before a conditional download, before an upload that shouldn't silently overwrite, or as a lightweight post-delete confirmation.
When to Use
- Pre-download guard: Confirm an expected report or export exists before attempting
object/download, avoiding aNoSuchKeyerror deep in a pipeline. - Overwrite protection: Check whether a destination key is already occupied before
object/upload, when the workflow should never silently replace existing data. - Post-delete confirmation: Verify an object is actually gone after
object/delete, useful in compliance/erasure workflows that need positive confirmation. - Idempotent provisioning: Skip re-uploading a static asset or template if it's already present at the target key.
Configuration
Connection
Credentials and region are not fields on this operation. Wire an S3 Server satellite node into this node's input. The satellite holds the vault credential (
ApiKey type — Username = access key ID, Password = secret key), the target AWS region, and an optional Service URL override for S3-compatible backends. Its values are merged onto this node at execution time and take precedence over anything set locally. See S3 Server (satellite) for the full field reference.
Tenant-prefixed:
objectKey is auto-prepended with tenants/{tenantId}/ before the request is sent to S3. The value you type is what other S3 nodes in this workflow should reuse; the output's effectiveObjectKey field carries the literal key actually probed, for use with the AWS console, CLI, or other external tools.
Operation Fields
| Field | Required | Description |
|---|---|---|
bucketName | Required | Bucket containing the object to probe. |
objectKey | Required | S3 object key to check for existence. |
Sample Configuration
// Credentials + region resolved from the connected S3 Server satellite — see s3-server-satellite.html
{
"resource": "object",
"operation": "exists",
"bucketName": "acme-prod-reports",
"objectKey": "monthly/{{ $now | date: 'YYYY/MM' }}/billing-summary.pdf"
}
Validation Errors
| Error Code | Cause & Resolution |
|---|---|
MISSING_TENANT_CONTEXT | No tenant context was available in the execution environment. Fails before any S3 call is made. |
AccessDenied | The IAM identity lacks s3:HeadObject (or s3:GetObject, which also grants HEAD) on the target bucket/key. |
NoSuchBucket | The specified bucket does not exist. This routes to the error port — it is distinct from the object itself not existing, which is a normal exists: false success result. |
Output
Success Port
| Field | Type | Description |
|---|---|---|
status | string | success — returned whether the object exists or not. A missing object is a normal result, not an error. |
errorCode | string | Empty string on success. |
bucketName | string | The bucket that was probed. |
objectKey | string | Object key as provided by the user (without tenant prefix). |
effectiveObjectKey | string | Actual S3 key probed, including the tenants/{tenantId}/ prefix. |
exists | boolean | true if the object exists, false otherwise. |
Error Port
On failure, activates with errorCode and errorMessage. A non-existent object is not a failure — it's a successful result with exists: false. Only genuine AWS errors (permissions, missing bucket, network) route to the error port.
Sample Output
{
"status": "success",
"errorCode": "",
"bucketName": "acme-prod-reports",
"objectKey": "monthly/2026/05/billing-summary.pdf",
"effectiveObjectKey": "tenants/1024/monthly/2026/05/billing-summary.pdf",
"exists": true
}
Expression Reference
| Expression | Result |
|---|---|
{{ $node.CheckReportExists.output.exists }} | Boolean gate — branch an If Condition to object/download vs. a fallback generation path. |
{{ $node.CheckReportExists.output.effectiveObjectKey }} | The literal S3 key probed — log for audit or pass to an external tool. |
Node Policies & GuardRails
| Policy Area | Recommendation |
|---|---|
| Credential Storage | Store credentials in the vault via the connected S3 Server satellite. Never hardcode. |
| IAM Permissions | Grant s3:GetObject (or the narrower s3:HeadObject, where supported) scoped to the specific bucket ARN and key prefix. |
| Don't Treat "Not Found" as an Error | Route on the exists output field with an If Condition, not on the error port — a missing object is a normal, successful result of this operation. |
| Prefer This Over a Full Download for Existence Checks | Use object/exists instead of a full object/download when only presence matters — it's a HEAD request, not a GET, so it doesn't transfer the object body. |
Examples
Example 1: Pre-Download Existence Guard
Before attempting to download and email a customer's invoice, confirm the file actually exists to avoid a downstream NoSuchKey failure.
// Node: CheckInvoiceExists (S3 — object/exists)
{
"bucketName": "acme-billing-archive",
"objectKey": "{{ $node.LookupInvoice.output.s3Key }}"
}
// Node: IfExists (If Condition)
// exists == true → object/download → EmailInvoice
// exists == false → NotifyOps("Expected invoice missing: " + objectKey)
Example 2: Overwrite-Safe Upload
Before publishing a versioned static asset, confirm the target key isn't already occupied — the workflow should never silently overwrite a previously published version.
// Node: CheckAssetExists (S3 — object/exists)
{
"bucketName": "acme-static-assets",
"objectKey": "v{{ $node.BuildInfo.output.version }}/bundle.js"
}
// Node: GuardOverwrite (If Condition)
// exists == false → object/upload
// exists == true → FailBuild("Version already published — bump the version")
Example 3: Post-Erasure Confirmation
After a GDPR right-to-erasure delete, positively confirm the object is gone before closing out the compliance ticket.
// Node: DeleteUserData (S3 — object/delete)
// Node: ConfirmErasure (S3 — object/exists)
{
"bucketName": "acme-user-documents",
"objectKey": "users/{{ $node.ErasureRequest.output.userId }}/{{ $loop.currentItem.key }}"
}
// Node: VerifyGone (If Condition)
// exists == false → CloseComplianceTicket
// exists == true → AlertComplianceTeam("Erasure did not remove object")