floci-io/floci · error · AwsException

BadRequestException

BadRequestException

Error message

Invalid resource ARN: ${arn}

What it means

Thrown by CodeDeploy's BatchGetDeployments when any requested id is missing from the region's deployment store; the stream throws on the first null lookup. As with batchGetApplications, this is stricter than real AWS, where BatchGetDeployments omits unknown ids from the response.

Source

Thrown at src/main/java/io/github/hectorvent/floci/core/common/SharedTagsController.java:249

        }
        return (values == null) ? List.of() : List.copyOf(values);
    }

    private String readResourceArn(String body) {
        try {
            JsonNode node = objectMapper.readTree((body == null || body.isBlank()) ? "{}" : body);
            return node.path("resourceArn").asText(null);
        } catch (Exception e) {
            throw new AwsException("BadRequestException", e.getMessage(), 400);
        }
    }

    private TagHandler resolveHandler(String arn) {
        String serviceKey;
        try {
            serviceKey = AwsArnUtils.parse(arn).service();
        } catch (IllegalArgumentException e) {
            throw new AwsException("BadRequestException",
                    "Invalid resource ARN: " + arn, 400);
        }
        TagHandler handler = handlersByServiceKey.get(serviceKey);
        if (handler == null) {
            // Surface an unregistered service as an invalid-ARN error so floci's
            // internal routing isn't leaked to the client.
            throw new AwsException("BadRequestException",
                    "Invalid resource ARN: " + arn, 400);
        }
        return handler;
    }
}

View on GitHub (pinned to 62ff490619)

Solutions

  1. Filter requested ids against ListDeployments output before batching.
  2. Drop persisted ids older than the current emulator session when storage is memory-based.
  3. Fall back to per-id GetDeployment with a try-catch if you must tolerate missing ids.

Example fix

// before
BatchGetDeploymentsResponse resp = codedeploy.batchGetDeployments(
    r -> r.deploymentIds(List.of("d-1", "d-gone", "d-3")));

// after
Set<String> live = new HashSet<>(codedeploy.listDeployments().deployments());
List<String> wanted = List.of("d-1", "d-gone", "d-3").stream().filter(live::contains).toList();
BatchGetDeploymentsResponse resp = codedeploy.batchGetDeployments(r -> r.deploymentIds(wanted));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> live = new HashSet<>(codedeploy.listDeployments().deployments());
List<String> safe = deploymentIds.stream().filter(live::contains).toList();

Try / catch

try {
    codedeploy.batchGetDeployments(r -> r.deploymentIds(ids));
} catch (DeploymentDoesNotExistException e) {
    // one id is stale — filter against ListDeployments and retry
}

Prevention

When it happens

Trigger: BatchGetDeployments with a list containing at least one stale, deleted, cross-region, or malformed deployment id; bulk status pollers feeding unfiltered ids into one batch call.

Common situations: Code ported from real AWS expecting lenient batch semantics; mixing deployment ids collected before an emulator restart with fresh ones.

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


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/fd5d89bcc95f0122. Report an issue: GitHub.