Skip to main content
← Back to list
01Issue
FeatureClosedExtensions
AssigneesNone

@swamp/s3-datastore: first-attempt 403 masked as "UnknownError" from AWS SDK deserializer

Opened by stack72 · 4/20/2026

Summary

When the S3 client built by @swamp/s3-datastore hits an HTTP 403 (e.g. InvalidAccessKeyId from DigitalOcean Spaces), the first call through the extension surfaces the error as a generic UnknownError originating from the bundled AWS SDK's XML protocol deserializer. On a subsequent attempt (a separate swamp invocation), the same underlying auth failure surfaces correctly as InvalidAccessKeyId with full $metadata. The first-attempt masking hides the real cause and wastes debugging time.

Stack trace (first attempt)

Observed during swamp model create @swamp/issue-lifecycle issue-1 against a DO Spaces bucket:

{
  "error": "UnknownError",
  "stack": "    at ProtocolLib.getErrorSchemaOrThrowBaseException (file:///.../datastore-bundles/7c811b12/s3.js:13151:63)
    at AwsRestXmlProtocol3.handleError (file:///.../datastore-bundles/7c811b12/s3.js:14851:65)
    at AwsRestXmlProtocol3.deserializeResponse (file:///.../datastore-bundles/7c811b12/s3.js:6251:22)
    ..."
}

Stack trace (second attempt, same credentials)

Same command, seconds later:

"$fault": "client",
"$metadata": {
  "httpStatusCode": 403,
  "requestId": "tx0000083c5e12c596eed6c-0069e66dc8-b04dd851-sfo3a",
  "attempts": 1
},
"Code": "InvalidAccessKeyId"

Same credentials, same bucket, same region — but only the second surfaces an actionable error.

Likely cause

The bundled AWS SDK's XML error deserializer rejects the 403 response body on first contact — most likely because DigitalOcean Spaces returns a non-XML or subtly-malformed error body on some responses (for InvalidAccessKeyId before signature validation completes, some S3-compatible providers return a plain-text or HTML body that fails the SDK's schema assertion). The second attempt presumably hits a different code path (retry, warmed-up client, endpoint re-negotiation) that returns a well-formed XML fault.

Either way, the user-facing outcome is a bare UnknownError stack with no hint that the failure is authentication.

Expected

The extension should wrap S3 operations and catch SDK errors that surface without a parseable body, then surface them with at least:

  • HTTP status code (from $metadata.httpStatusCode when present on the raw error, or the response itself)
  • A short body preview (first N bytes) if the body isn't parseable
  • An auth-specific hint when the status is 401/403, naming the credential source (AWS profile, env var AWS_ACCESS_KEY_ID, IMDS, etc.) so users know where to look

This is consistent with how other swamp extensions surface provider-specific auth failures.

Scope

Fix belongs in the @swamp/s3-datastore extension's S3 call wrapping — wherever the extension invokes the bundled SDK (pullChanged, pushChanged, head/list/put/get paths). Catch Error from the SDK, inspect $metadata / Code / httpStatusCode, and surface a structured error that core swamp can display usefully. No change required in the bundled AWS SDK itself.

Environment

  • swamp: 20260206.200442.0-sha
  • Platform: macOS (darwin 25.3.0)
  • Provider: DigitalOcean Spaces (sfo3 region)
  • Datastore config: @swamp/s3-datastore with endpoint: https://sfo3.digitaloceanspaces.com
  • Credentials: AWS profile (AWS_PROFILE=<name>)

Automoved by swampadmin from https://github.com/systeminit/swamp-extensions/issues/74

02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED

Closed

4/20/2026, 9:27:22 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

stack72 commented 4/20/2026, 9:27:20 PM

Sign in to post a ripple.