floci-io/floci · error · AwsException
BadRequestException
BadRequestException
Error message
Reserved tag key ${key} can only be supplied during resource creation. What it means
Thrown by the emulator's job-completion handler (backing PutJobSuccessResult and PutJobFailureResult) when the referenced job's status is neither 'Created' nor 'InProgress'. A job that already reported Succeeded or Failed cannot be completed again; every completion call must target a live job. The nonce-free lookup is by jobId only, then the state guard fires.
Source
Thrown at src/main/java/io/github/hectorvent/floci/core/common/ReservedTags.java:98
*/
public static Map<String, String> stripApiGatewayReservedTags(Map<String, String> tags) {
Map<String, String> stripped = stripReservedTags(tags);
stripped.remove(DEPRECATED_API_GATEWAY_CUSTOM_ID_KEY);
return stripped;
}
/**
* API Gateway update-path guard. An id override only makes sense at create time, so both the
* reserved keys and the deprecated custom-id key are rejected here, with API Gateway's declared
* error code rather than the {@code ValidationException} the shared guard uses.
*/
public static void rejectApiGatewayReservedTagsOnUpdate(Map<String, String> tags) {
if (tags == null) {
return;
}
for (String key : tags.keySet()) {
if (isReserved(key) || DEPRECATED_API_GATEWAY_CUSTOM_ID_KEY.equals(key)) {
throw new AwsException(
BAD_REQUEST_EXCEPTION,
"Reserved tag key " + key + " can only be supplied during resource creation.",
400
);
}
}
}
public static void rejectReservedTagsOnUpdate(Map<String, String> tags) {
if (tags == null) {
return;
}
for (String key : tags.keySet()) {
if (isReserved(key)) {
throw new AwsException(
VALIDATION_EXCEPTION,
"Reserved tag keys with prefix " + RESERVED_PREFIX + " can only be supplied during resource creation.",
400View on GitHub (pinned to 62ff490619)
Solutions
- Guard PutJobSuccessResult/PutJobFailureResult with a try-catch for InvalidJobStateException and treat it as already-reported
- Report exactly one terminal result per jobId — move the success call out of finally blocks so it cannot run after a failure report
- Check GetJobDetails status before retrying a completion call
Example fix
// before
try { runWork(); client.putJobSuccessResult(...); } catch (Exception e) { client.putJobFailureResult(...); } finally { client.putJobSuccessResult(...); }
// after
try {
runWork();
client.putJobSuccessResult(...);
} catch (Exception e) {
client.putJobFailureResult(r -> r.jobId(jobId).failureDetails(...));
} Defensive patterns
Strategy: try-catch
Try / catch
try {
client.putJobSuccessResult(r -> r.jobId(jobId).executionDetails(...));
} catch (InvalidJobStateException alreadyDone) {
logger.warn("job {} already completed; skipping duplicate result", jobId);
} Prevention
- Submit exactly one terminal result per job; never put success reporting in a finally block
- Check job status via GetJobDetails before resubmitting a result after a crash
When it happens
Trigger: Calling PutJobSuccessResult after PutJobFailureResult for the same jobId (or vice versa); retrying a completion that already succeeded; completing a job whose pipeline execution was superseded and the job finalized.
Common situations: Worker retry logic that resubmits results after a timeout; long-running workers that finish after a newer execution already closed the job; bugs that submit both success and failure paths (e.g. success in a finally block after an exception already reported failure).
Understand the failure class
Background: BadRequestException (HTTP 400) — NestJS 'Bad Request' Errors: Why They Fire and How to Fix Them — this error's family across 4 libraries.
Related errors
- ${description} file not found or not readable: ${path}
- PipelineNameInUseException
- ActionTypeAlreadyExistsException
- TLS enabled but no certificate provided and self-signed gene
- Failed to write self-signed TLS certificate
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/1eb3fee2f039158d.
Report an issue: GitHub.