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
- Set the S3 origin's OriginAccessIdentity to the full form: origin-access-identity/cloudfront/<OAI-id>
- Create the OAI with CreateCloudFrontOriginAccessIdentity first and reuse the exact value AWS/Floci returns
- 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
- Always compose the value as "origin-access-identity/cloudfront/" + oaiId from the create response
- Validate the distribution config shape in tests before serving traffic through it
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
- InvalidIfMatchVersion
- InvalidArgument
- InconsistentQuantities
- InvalidIfMatchVersion
- DistributionNotDisabled
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/5b57a942bd6bd854.
Report an issue: GitHub.