{"record":{"id":"fd5d89bcc95f0122","repo":"floci-io/floci","slug":"badrequestexception-fd5d89","errorCode":"BadRequestException","errorMessage":"Invalid resource ARN: ${arn}","messagePattern":"Invalid resource ARN: (.+?)","errorType":"http","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/core/common/SharedTagsController.java","lineNumber":249,"sourceCode":"        }\n        return (values == null) ? List.of() : List.copyOf(values);\n    }\n\n    private String readResourceArn(String body) {\n        try {\n            JsonNode node = objectMapper.readTree((body == null || body.isBlank()) ? \"{}\" : body);\n            return node.path(\"resourceArn\").asText(null);\n        } catch (Exception e) {\n            throw new AwsException(\"BadRequestException\", e.getMessage(), 400);\n        }\n    }\n\n    private TagHandler resolveHandler(String arn) {\n        String serviceKey;\n        try {\n            serviceKey = AwsArnUtils.parse(arn).service();\n        } catch (IllegalArgumentException e) {\n            throw new AwsException(\"BadRequestException\",\n                    \"Invalid resource ARN: \" + arn, 400);\n        }\n        TagHandler handler = handlersByServiceKey.get(serviceKey);\n        if (handler == null) {\n            // Surface an unregistered service as an invalid-ARN error so floci's\n            // internal routing isn't leaked to the client.\n            throw new AwsException(\"BadRequestException\",\n                    \"Invalid resource ARN: \" + arn, 400);\n        }\n        return handler;\n    }\n}\n","sourceCodeStart":231,"sourceCodeEnd":262,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/core/common/SharedTagsController.java#L231-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"Code ported from real AWS expecting lenient batch semantics; mixing deployment ids collected before an emulator restart with fresh ones.","solutions":["Filter requested ids against ListDeployments output before batching.","Drop persisted ids older than the current emulator session when storage is memory-based.","Fall back to per-id GetDeployment with a try-catch if you must tolerate missing ids."],"exampleFix":"// before\nBatchGetDeploymentsResponse resp = codedeploy.batchGetDeployments(\n    r -> r.deploymentIds(List.of(\"d-1\", \"d-gone\", \"d-3\")));\n\n// after\nSet<String> live = new HashSet<>(codedeploy.listDeployments().deployments());\nList<String> wanted = List.of(\"d-1\", \"d-gone\", \"d-3\").stream().filter(live::contains).toList();\nBatchGetDeploymentsResponse resp = codedeploy.batchGetDeployments(r -> r.deploymentIds(wanted));","handlingStrategy":"validation","validationCode":"Set<String> live = new HashSet<>(codedeploy.listDeployments().deployments());\nList<String> safe = deploymentIds.stream().filter(live::contains).toList();","typeGuard":null,"tryCatchPattern":"try {\n    codedeploy.batchGetDeployments(r -> r.deploymentIds(ids));\n} catch (DeploymentDoesNotExistException e) {\n    // one id is stale — filter against ListDeployments and retry\n}","preventionTips":["Pre-filter batch id lists against ListDeployments — Floci fails the whole batch on one bad id.","Drop ids older than the current emulator session.","Degrade to per-id GetDeployment with try-catch when partial results are acceptable."],"tags":["codedeploy","aws-emulator","resource-not-found","batch-semantics","aws-divergence"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}