floci-io/floci · error · AwsException

InvalidArgument

InvalidArgument

Error message

The S3 origin access identity is invalid.

What it means

When Floci's CloudFront serving path forwards a request to an S3 origin, it parses the OriginAccessIdentity field of the S3 origin config. The value must have the exact shape origin-access-identity/cloudfront/<id> (a single non-empty id segment after the prefix, no extra slashes); a leading slash is tolerated. Anything else throws InvalidArgument (HTTP 400).

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontServingController.java:369

            s3Service.authorizeCloudFrontOaiGetObject(
                    bucket, key, oaiId, oai.getS3CanonicalUserId());
            return;
        }
        s3Service.authorizeAnonymousGetObject(bucket, key);
    }

    private static String originAccessIdentityId(Origin origin) {
        Map<String, String> config = origin.getS3OriginConfig();
        String value = config != null ? config.get("OriginAccessIdentity") : null;
        if (value == null || value.isBlank()) {
            return null;
        }
        String normalized = value.startsWith("/") ? value.substring(1) : value;
        String prefix = "origin-access-identity/cloudfront/";
        if (!normalized.startsWith(prefix)
                || normalized.length() == prefix.length()
                || normalized.substring(prefix.length()).contains("/")) {
            throw new AwsException(
                    "InvalidArgument", "The S3 origin access identity is invalid.", 400);
        }
        return normalized.substring(prefix.length());
    }

    /** Fetches from a custom (non-S3) origin. {@code forwardUri} already includes the origin path. */
    private OriginResponse fetchFromCustomOrigin(Origin origin, String forwardUri, String rawQuery,
                                                 String viewerScheme, boolean includeBody) {
        try {
            URI target = buildCustomOriginUri(
                    origin, viewerScheme, forwardUri, rawQuery);
            HttpRequest.Builder rb = HttpRequest.newBuilder()
                    .uri(target)
                    .timeout(Duration.ofSeconds(30));
            if (includeBody) {
                rb.GET();
            } else {
                rb.method("HEAD", HttpRequest.BodyPublishers.noBody());

View on GitHub (pinned to 62ff490619)

Solutions

  1. Set the S3 origin's OriginAccessIdentity to the full form: origin-access-identity/cloudfront/<OAI-id>
  2. Create the OAI with CreateCloudFrontOriginAccessIdentity first and reuse the exact value AWS/Floci returns
  3. Fix the distribution with UpdateDistribution, then retry the serving request

Example fix

// before
Origins.builder().items(List.of(Origin.builder()
    .id("s3-origin")
    .domainName("my-bucket.s3.amazonaws.com")
    .s3OriginConfig(S3OriginConfig.builder()
        .originAccessIdentity("E127EXAMPLE51Z")
        .build())
    .build())).build();

// after
String oaiId = cloudFrontClient.createCloudFrontOriginAccessIdentity(r -> r
    .cloudFrontOriginAccessIdentityConfig(
        CloudFrontOriginAccessIdentityConfig.builder()
            .callerReference("oai-1")
            .comment("bucket oai").build()))
    .cloudFrontOriginAccessIdentity().id();
Origins.builder().items(List.of(Origin.builder()
    .id("s3-origin")
    .domainName("my-bucket.s3.amazonaws.com")
    .s3OriginConfig(S3OriginConfig.builder()
        .originAccessIdentity("origin-access-identity/cloudfront/" + oaiId)
        .build())
    .build())).build();
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern OAI =
    Pattern.compile("^/?origin-access-identity/cloudfront/[^/]+$");

static boolean isValidOriginAccessIdentity(String v) {
    return v != null && OAI.matcher(v).matches();
}

// before creating the distribution:
if (!isValidOriginAccessIdentity(origin.s3OriginConfig().originAccessIdentity())) {
    throw new IllegalArgumentException("OriginAccessIdentity must be origin-access-identity/cloudfront/<id>");
}

Try / catch

catch (CloudFrontException e) {
    if ("InvalidArgument".equals(e.awsErrorDetails().errorCode())
            && e.getMessage().contains("origin access identity")) {
        // fix the S3 origin config to the full prefix form and retry the request
    } else { throw e; }
}

Prevention

When it happens

Trigger: A distribution whose S3 origin sets OriginAccessIdentity to a bare id (e.g. E2XXXX), an empty segment after the prefix, or a value with an additional slash — and then a request is served through that distribution (the data-plane path, not the management API).

Common situations: Hand-written distribution JSON that puts the OAI id alone in the field; copying the cloudfront portion of the ARN incorrectly; Terraform/CloudFormation configs where the interpolation produced an empty id.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/5b57a942bd6bd854. Report an issue: GitHub.