floci-io/floci · error · AwsException
StreamingDistributionNotDisabled
StreamingDistributionNotDisabled
Error message
The streaming distribution you are trying to delete has not been disabled.
What it means
A streaming distribution must be disabled before it can be deleted; Floci checks existing.isEnabled() in deleteStreamingDistribution and throws StreamingDistributionNotDisabled (HTTP 409 Conflict) when the distribution is still enabled. The ETag check runs first, so a valid If-Match is still required. AWS behaves identically, and disabling is itself an update that requires the current ETag and takes the distribution out of deployment.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/cloudfront/CloudFrontService.java:1339
}
updated.setId(id);
updated.setArn(existing.getArn());
updated.setDomainName(existing.getDomainName());
updated.setStatus("Deployed");
updated.setLastModifiedTime(Instant.now());
updated.setEtag(UUID.randomUUID().toString());
streamingDistStore.put(id, updated);
return updated;
}
public synchronized void deleteStreamingDistribution(String id, String ifMatch) {
StreamingDistribution existing = getStreamingDistribution(id);
if (!existing.getEtag().equals(ifMatch)) {
throw new AwsException("InvalidIfMatchVersion",
"The If-Match version is missing or not valid for the resource.", 400);
}
if (existing.isEnabled()) {
throw new AwsException("StreamingDistributionNotDisabled",
"The streaming distribution you are trying to delete has not been disabled.", 409);
}
streamingDistStore.delete(id);
}
// ── Field-Level Encryption Configs ────────────────────────────────────────
public synchronized FieldLevelEncryptionConfig createFieldLevelEncryptionConfig(
FieldLevelEncryptionConfig cfg) {
cfg.setId(UUID.randomUUID().toString());
cfg.setLastModifiedTime(Instant.now());
cfg.setEtag(UUID.randomUUID().toString());
fleConfigStore.put(cfg.getId(), cfg);
return cfg;
}
public FieldLevelEncryptionConfig getFieldLevelEncryptionConfig(String id) {
return fleConfigStore.get(id).orElseThrow(() ->View on GitHub (pinned to 62ff490619)
Solutions
- First disable: GetStreamingDistributionConfig, then UpdateStreamingDistribution with Enabled=false and the current ETag
- Then GetStreamingDistribution again for the new ETag and call DeleteStreamingDistribution with it
- In cleanup code, catch StreamingDistributionNotDisabled and run the disable-then-delete sequence
Example fix
// before
cloudFrontClient.deleteStreamingDistribution(r -> r.id(distId).ifMatch(etag));
// after
GetStreamingDistributionConfigResponse cfg =
cloudFrontClient.getStreamingDistributionConfig(r -> r.id(distId));
cloudFrontClient.updateStreamingDistribution(r -> r
.id(distId)
.ifMatch(cfg.eTag())
.streamingDistributionConfig(cfg.streamingDistributionConfig().toBuilder()
.enabled(false)
.build()));
String newEtag = cloudFrontClient.getStreamingDistributionConfig(r -> r.id(distId)).eTag();
cloudFrontClient.deleteStreamingDistribution(r -> r.id(distId).ifMatch(newEtag)); Defensive patterns
Strategy: try-catch
Validate before calling
GetStreamingDistributionResponse dist = cloudFrontClient.getStreamingDistribution(r -> r.id(distId));
if (dist.streamingDistribution().enabled()) {
// must disable before delete
} Try / catch
try {
cloudFrontClient.deleteStreamingDistribution(r -> r.id(distId).ifMatch(etag));
} catch (CloudFrontException e) {
if ("StreamingDistributionNotDisabled".equals(e.awsErrorDetails().errorCode())) {
var cfg = cloudFrontClient.getStreamingDistributionConfig(r -> r.id(distId));
cloudFrontClient.updateStreamingDistribution(r -> r.id(distId)
.ifMatch(cfg.eTag())
.streamingDistributionConfig(cfg.streamingDistributionConfig().toBuilder()
.enabled(false).build()));
String newEtag = cloudFrontClient.getStreamingDistributionConfig(r -> r.id(distId)).eTag();
cloudFrontClient.deleteStreamingDistribution(r -> r.id(distId).ifMatch(newEtag));
} else { throw e; }
} Prevention
- Standard teardown order: disable (update) → re-read ETag → delete
- Remember each update rotates the ETag, so re-read after disabling
When it happens
Trigger: DeleteStreamingDistribution on a distribution whose StreamingDistributionConfig.Enabled is true. Typical in teardown scripts that skip the disable step, or that disable and delete so fast the disable update was never actually sent.
Common situations: CI/CD teardown pipelines deleting distributions in one step; test cleanup between runs; forgetting that disable is a separate UpdateStreamingDistribution call with its own If-Match.
Related errors
- DistributionNotDisabled
- Boot hook execution interrupted
- Boot hook execution failed
- Hook script failed: %s exited with code %d
- Hook script timed out after %d seconds: %s
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/45db4bce046c8205.
Report an issue: GitHub.