S3 CORS Configuration: Common Pitfalls That Cause Invalid JSON Errors in AWS SDK for JavaScript v3
The AWS SDK for JavaScript v3 expects a typed JavaScript object matching the PutBucketCorsRequest interface, not raw JSON, and "invalid JSON" errors typically indicate a mismatch between your object structure and the required CORSRule, CORSConfiguration, or PutBucketCorsRequest shapes defined in the SDK.
When configuring Cross-Origin Resource Sharing (CORS) for Amazon S3 using the AWS SDK for JavaScript v3, the PutBucketCorsCommand does not accept a raw JSON payload. Instead, the SDK validates your input against TypeScript interfaces defined in clients/client-s3/src/models/models_0.ts and serializes the object to XML before transmission. Understanding this serialization pipeline is critical to diagnosing cryptic "invalid JSON format" or "Invalid request payload" errors that surface during development.
Why You Get "Invalid JSON" Errors When Configuring S3 CORS
The AWS SDK for JavaScript v3 translates your JavaScript object into an XML document that matches the S3 REST API specification for the PUT ?cors operation. Before any network request is dispatched, the SDK's protocol serializer (referenced in clients/client-s3/src/schemas/schemas_0.ts at line 3187) validates the input against the operation schema. If your object lacks required fields, uses incorrect property names, or violates type constraints, the serializer throws an error that often manifests as "invalid JSON format" because the SDK treats the malformed object as unparsable input.
Seven Common S3 CORS Configuration Mistakes
Missing Required Fields on CORSRule
Every CORSRule must include the AllowedMethods and AllowedOrigins properties as arrays. In clients/client-s3/src/models/models_0.ts, the CORSRule interface explicitly marks these fields as required: AllowedMethods: string[]; AllowedOrigins: string[];. If either is undefined, the serializer cannot construct the XML elements and aborts with a payload error.
Incorrect Property Casing
The SDK performs exact property name matching. Using lowercase allowedMethods or allowedOrigins instead of the PascalCase AllowedMethods and AllowedOrigins causes the SDK to ignore the keys, resulting in missing required values. Always use the exact interface keys: AllowedMethods, AllowedOrigins, AllowedHeaders, ExposeHeaders, MaxAgeSeconds, and ID.
Scalars Instead of Arrays
Supplying a single string like "GET" instead of an array ["GET"] breaks the serializer. The protocol implementation expects to iterate over these values to generate multiple XML elements (e.g., <AllowedMethod>GET</AllowedMethod>). Wrap single values in arrays: AllowedMethods: ["GET"].
Malformed JSON Syntax in Object Literals
JavaScript object literals are not JSON. Trailing commas after the last property or comments (// ...) inside object definitions create parse errors before the SDK ever sees the data. Remove trailing commas and use plain object literals without comments.
Missing CORSConfiguration Wrapper
A frequent structural error is passing the array of rules directly instead of nesting it inside a CORSConfiguration object. The PutBucketCorsRequest shape requires this exact hierarchy: { Bucket: "...", CORSConfiguration: { CORSRules: [...] } }. Providing { CORSRules: [...] } at the top level leaves CORSConfiguration undefined, causing validation to fail.
Incorrectly Typed MaxAgeSeconds
The MaxAgeSeconds field must be a number, not a string. Passing "3000" instead of 3000 results in invalid XML generation, as the serializer emits the string value verbatim where an integer is required by the S3 API schema.
Exceeding Service Limits
While not strictly a JSON format error, exceeding the S3 limits of 100 CORS rules or a total configuration size greater than 64 KB can cause the SDK to reject the payload preemptively or the service to return errors that the SDK surfaces as client-side validation failures.
How the SDK Serializes Your CORS Configuration
When you call new PutBucketCorsCommand(input), the middleware stack performs three critical steps:
- Schema Validation: The input is checked against the
PutBucketCorsoperation schema inclients/client-s3/src/schemas/schemas_0.ts. - XML Serialization: The
s3protocol serializer converts the JavaScript object to an XML document matching the S3 CORS API specification. - Request Construction: The generated XML is attached to the HTTP request body and sent to S3.
If the input object does not satisfy the TypeScript definitions, the serializer throws before any network call, surfacing as an "invalid JSON" error.
Correct S3 CORS Configuration Examples
Minimal Valid Configuration
This example matches the exact structure defined in clients/client-s3/src/models/models_0.ts:
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
const corsConfig = {
Bucket: "my-example-bucket",
CORSConfiguration: {
CORSRules: [
{
ID: "AllowGETFromAnyOrigin",
AllowedMethods: ["GET"],
AllowedOrigins: ["*"],
AllowedHeaders: ["*"],
ExposeHeaders: ["ETag"],
MaxAgeSeconds: 3000,
},
],
},
};
await client.send(new PutBucketCorsCommand(corsConfig));
Multiple Rules Configuration
When defining multiple origins or methods, ensure each rule maintains the required array structure:
const multiRuleConfig = {
Bucket: "my-example-bucket",
CORSConfiguration: {
CORSRules: [
{
ID: "ReadOnly",
AllowedMethods: ["GET", "HEAD"],
AllowedOrigins: ["https://example.com"],
AllowedHeaders: ["*"],
MaxAgeSeconds: 600,
},
{
ID: "WriteOnly",
AllowedMethods: ["PUT", "POST"],
AllowedOrigins: ["https://api.example.com"],
AllowedHeaders: ["Authorization", "Content-Type"],
ExposeHeaders: ["ETag", "x-amz-request-id"],
MaxAgeSeconds: 1200,
},
],
},
};
await client.send(new PutBucketCorsCommand(multiRuleConfig));
Debugging with SDK Logging
To inspect the generated XML and verify your configuration reaches the serializer correctly, enable logging:
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";
const client = new S3Client({
region: "us-east-1",
logger: console
});
await client.send(new PutBucketCorsCommand(corsConfig));
The console output will display the final XML payload, allowing you to verify that AllowedMethod and AllowedOrigin elements are correctly generated from your arrays.
Summary
- The AWS SDK for JavaScript v3 validates against TypeScript interfaces, not JSON schema, when processing
PutBucketCorsCommand. - Required fields are non-negotiable: Every
CORSRulemust includeAllowedMethodsandAllowedOriginsas arrays. - Property names are case-sensitive: Use
AllowedMethods, notallowedMethods. - Structure matters: Always wrap rules in
{ CORSConfiguration: { CORSRules: [...] } }. - Types must match:
MaxAgeSecondsrequires a number, not a string. - Limits apply: Maximum 100 rules and 64 KB total configuration size.
- Source authority: The shapes are defined in
clients/client-s3/src/models/models_0.tsand serialized viaclients/client-s3/src/schemas/schemas_0.ts.
Frequently Asked Questions
Does the AWS SDK for JavaScript v3 send JSON to S3 for CORS configuration?
No. The SDK accepts a JavaScript object and serializes it to XML according to the S3 REST API specification. The "invalid JSON" error message refers to the SDK's internal validation failure when your object does not match the required TypeScript interfaces, not to the wire format sent to S3.
Why am I seeing "Invalid JSON format" when I haven't sent any JSON?
This error occurs during the SDK's client-side validation phase. When you instantiate PutBucketCorsCommand, the middleware validates your input object against the operation schema defined in clients/client-s3/src/schemas/schemas_0.ts. If the object structure deviates from the expected shape—such as missing required fields or incorrect nesting—the serializer reports the object as unparsable, often using "invalid JSON" as the error descriptor.
What are the exact required fields for a CORSRule in the AWS SDK?
According to the CORSRule interface in clients/client-s3/src/models/models_0.ts, only AllowedMethods and AllowedOrigins are strictly required, both typed as string[]. All other fields—ID, AllowedHeaders, ExposeHeaders, and MaxAgeSeconds—are optional, though MaxAgeSeconds must be a number when provided.
How can I verify my CORS configuration before sending it to S3?
Enable the SDK's built-in logger by passing logger: console to your S3Client constructor. This outputs the generated XML payload to your console, allowing you to verify that required elements like <AllowedMethod> and <AllowedOrigin> are present and correctly formatted before the HTTP request is dispatched to the S3 service.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →