InvalidSpotFleetRequestConfig: Parameter: SpotFleetRequestConfig.ValidUntil is invalid
Checkboxes for prior research
- [x] I've gone through Developer Guide and API reference
- [x] I've checked AWS Forums and StackOverflow.
- [x] I've searched for previous similar issues and didn't find any solution.
Describe the bug
Regression where any Date sent in ValidFrom/ValidUntil causes an error to be thrown. The crash is reported by the server and seems to be related to the milliseconds.
Regression Issue
- [x] Select this option if this issue appears to be a regression.
SDK version number
@aws-sdk/client-ec2@npm:3.817.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
18.20.4
Reproduction Steps
Note that I've redacted some things.
yarn add @aws-sdk/client-ec2
// test.js
import { EC2Client, RequestSpotFleetCommand } from '@aws-sdk/client-ec2';
const client = new EC2Client({ region: 'us-east-1' });
const dryRun = false;
await client.send(new RequestSpotFleetCommand({
DryRun: dryRun,
SpotFleetRequestConfig: {
IamFleetRole: 'arn:aws:iam::REDACTED',
AllocationStrategy: 'capacityOptimized',
TargetCapacity: 1,
ValidUntil: new Date(Date.now() + (1000 * 60 * 60)),
TerminateInstancesWithExpiration: true,
Type: 'maintain',
TargetCapacityUnitType: 'units',
LaunchSpecifications: [
{
ImageId: 'ami-REDACTED',
BlockDeviceMappings: [
{
DeviceName: '/dev/sda1',
Ebs: {
DeleteOnTermination: true,
VolumeType: 'gp2',
VolumeSize: 8,
SnapshotId: 'snap-REDACTED',
},
},
],
IamInstanceProfile: {
Arn: 'arn:aws:iam::REDACTED',
},
KeyName: 'REDACTED',
SecurityGroups: [
{
GroupId: 'sg-REDACTED',
},
],
UserData: 'REDACTED',
InstanceRequirements: {
VCpuCount: {
Min: 8,
Max: 8,
},
MemoryMiB: {
Min: 4096,
},
SpotMaxPricePercentageOverLowestPrice: 100,
},
},
],
},
}));
node test.js
Note the ValidUntil prop.
Observed Behavior
node_modules/@smithy/smithy-client/dist-cjs/index.js:379
const response = new exceptionCtor({
^
InvalidSpotFleetRequestConfig: Parameter: SpotFleetRequestConfig.ValidUntil is invalid.
at throwDefaultError (node_modules/@smithy/smithy-client/dist-cjs/index.js:379:20)
at node_modules/@smithy/smithy-client/dist-cjs/index.js:388:5
at de_CommandError (node_modules/@aws-sdk/client-ec2/dist-cjs/index.js:17188:10)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async node_modules/@smithy/middleware-serde/dist-cjs/index.js:36:20
at async node_modules/@smithy/core/dist-cjs/index.js:193:18
at async node_modules/@smithy/middleware-retry/dist-cjs/index.js:320:38
at async node_modules/@aws-sdk/middleware-logger/dist-cjs/index.js:33:22
at <anonymous> (test.ts:5:18) {
'$fault': 'client',
'$metadata': {
httpStatusCode: 400,
requestId: '0856c9e6-159e-482c-8c2b-ee3fa2965def',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
Code: 'InvalidSpotFleetRequestConfig'
}
Expected Behavior
It should start the fleet request.
Possible Solution
Must support Date in ValidFrom/ValidUntil (as the typescript definitions suggests).
Additional Information/Context
Note that:
- If I set dryRun to true, it doesn't error.
- If I downgrade to @aws-sdk/client-ec2 3.427.0 it works.
- If I change
ValidUntilto{ toISOString: () => new Date(Date.now() + (1000 * 60 * 60)).toISOString().replace(/\.\d+Z$/, 'Z') }it works.
This suggests that the @aws-sdk/client-ec2 client calls Date.toISOString() on ValidFrom/ValidUntil and then sends to the server what is returned from those (e.g. 2025-05-26T21:37:50.051Z), however the server expects 2025-05-26T21:37:50Z (no milliseconds).
How am I the only person who seems to have hit this obvious bug in the JS SDK?
Related: https://github.com/boto/boto3/issues/714
Hey @mifi ,
Thanks for your feedback! I can reproduce this issue. I think the root cause is that - the service model accepts UTC format timestamp (for example - 2025-05-27T21:09:50Z ) for ValidUntil/ ValidFrom, but the SDKis sending Tue May 27 2025 14:19:32 GMT-0700 with new Date(Date.now() + (1000 * 60 * 60)) .
As you can see on JS SDK model file , the ValidFrom and ValidUntil are either Date type of undefined .
ValidFrom?: Date | undefined;
ValidUntil?: Date | undefined;
I will check with service team on this to identify if it's a designed behavior and there's a doc gap, or, if there's something wrong in service model.
Workaround
You can either use the workaround you have as a workaround, or convert the Date object to UTC format -
ValidUntil: new Date(
Date.UTC(
new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDate()+1,
new Date().getUTCHours()
)
),
@mifi does it succeed if you use the nearest second as the timestamp?
ValidUntil: new Date((Date.now() / 1000 | 0) * 1000 + (1000 * 60 * 60))
Our specification says that milliseconds are optional in the "date-time" format that this service is supposed to be using, but it may be that the server is rejecting milliseconds.
I don't think there is a bug in the client side SDK here, since we are adhering to the specification. Maybe the service error message needs to be clearer as to why it has rejected the milliseconds.
Got updates from service team -
You used a datetime format of Tue May 27 2025 14:19:32 GMT-0700 as the value for SpotFleetRequestConfig.ValidUntil and received an error. This is expected since our public api doc and the sdk doc linked both mention that the value for ValidUntil should be in UTC format YYYY-MM-DDTHH:MM:SSZ . We parse the inputted value in this format so other DateTime formats won't work.
Rounding to the nearest second workaround is working as service api doesn't receive milliseconds. I will bring it to my team. You can use @kuhe's proposed solution as a workaround.
Thanks.
This issue has not received a response in 1 week. If you still think there is a problem, please leave a comment to avoid the issue from automatically closing.
Shouldn’t this behavior be documented? It’s very unexpected and confusing behavior. I think the JS SDK should remove the milliseconds part from the timestamp before sending it to your API
As mentioned in comment above, it's documented both Service API docs and SDK API reference doc that ValidUntil should be in UTC format and SDK client side adheres to smithy specification.
The end date and time of the request, in UTC format (YYYY-MM-DDTHH:MM:SSZ). After the end date and time, no new Spot Instance requests are placed or able to fulfill the request. If no value is specified, the Spot Fleet request remains until you cancel it.
Since there's no further action item for SDK, we're going to close the issue.
This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.
In the SDK API reference doc it's just says that:
| ValidUntil | Date | undefined | The end date and time of the request, in UTC format (YYYY-MM-DDTHH:MM:SSZ). After the end date and time, no new Spot Instance requests are placed or able to fulfill the request. If no value is specified, the Spot Fleet request remains until you cancel it. |
Also the typescript types only allow a Date object or undefined to be passed. However the docs say nothing about the need to round the Date object to nearest second. Shouldn't it? If normal date objects are not accepted, shouldn't the API instead take a string instead of Date objects?
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.