floci-io/floci · error · AwsException
ValidationException
ValidationException
Error message
Dimensions filter requires a Key.
What it means
A Cost Explorer Filter of type Dimensions must carry a Key naming which dimension to match (SERVICE, REGION, ...). Floci evaluates filters while scanning usage lines and throws as soon as it hits a Dimensions node without a Key.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/ce/FilterExpressionEvaluator.java:71
if (dimensions.isObject() && !dimensions.isEmpty()) {
return matchDimensions(dimensions, line);
}
JsonNode tags = expression.path("Tags");
if (tags.isObject() && !tags.isEmpty()) {
return matchTags(tags, line);
}
JsonNode costCategories = expression.path("CostCategories");
if (costCategories.isObject() && !costCategories.isEmpty()) {
// No cost categories defined — never matches.
return false;
}
return true;
}
private static boolean matchDimensions(JsonNode node, UsageLine line) {
String key = node.path("Key").asText(null);
if (key == null || key.isEmpty()) {
throw new AwsException("ValidationException",
"Dimensions filter requires a Key.", 400);
}
Set<String> values = readValues(node.path("Values"));
Set<String> matchOptions = readValues(node.path("MatchOptions"));
boolean caseInsensitive = matchOptions.contains("CASE_INSENSITIVE");
String actual = dimensionValue(key, line);
return valueMatches(actual, values, caseInsensitive);
}
private static boolean matchTags(JsonNode node, UsageLine line) {
String key = node.path("Key").asText(null);
if (key == null || key.isEmpty()) {
throw new AwsException("ValidationException",
"Tags filter requires a Key.", 400);
}
Set<String> values = readValues(node.path("Values"));
Set<String> matchOptions = readValues(node.path("MatchOptions"));
boolean caseInsensitive = matchOptions.contains("CASE_INSENSITIVE");View on GitHub (pinned to 62ff490619)
Solutions
- Add Key to the Dimensions filter: {"Dimensions": {"Key": "SERVICE", "Values": ["Amazon EC2"]}}
- Use the SDK's builder (DimensionValues.builder().key(Dimension.SERVICE)) which makes the required shape obvious
- Validate filter JSON against the CE model before sending
Example fix
// before
Filter.builder().dimensions(d -> d.values("Amazon EC2")).build();
// after
Filter.builder().dimensions(d -> d.key(Dimension.SERVICE).values("Amazon EC2")).build(); Defensive patterns
Strategy: type-guard
Validate before calling
if (filter.dimensions() != null && (filter.dimensions().key() == null || filter.dimensions().key().isBlank())) {
throw new IllegalArgumentException("Dimensions filter requires Key");
} Type guard
function isDimensionFilter(f: unknown): f is { Dimensions: { Key: string; Values: string[] } } {
const d = (f as any)?.Dimensions;
return !!d && typeof d.Key === "string" && d.Key.length > 0 && Array.isArray(d.Values);
} Prevention
- Use the AWS SDK builder types — they surface required members at compile time
- Validate filter JSON with a schema before sending to CE
When it happens
Trigger: GetCostAndUsage / GetDimensionValues / GetCostAndUsageWithResources with Filter: {Dimensions: {Values: ["Amazon EC2"]}} — Values present but Key missing or empty.
Common situations: Hand-built filter JSON copied from an example that omitted Key; dynamically assembled filters where the key field is optional in the UI model but required by the API.
Related errors
- ValidationException
- ValidationException
- ValidationException
- ValidationException
- TLS enabled but no certificate provided and self-signed gene
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/0321cf02f2d1bbc8.
Report an issue: GitHub.