{"record":{"id":"fa6dcd5933ffe661","repo":"floci-io/floci","slug":"objectnotfoundexception","errorCode":"ObjectNotFoundException","errorMessage":"No scalable target found for service namespace: {serviceNamespace}, resource ID: {resourceId}, scalable dimension: {scalableDimension}","messagePattern":"No scalable target found for service namespace: (.+?), resource ID: (.+?), scalable dimension: (.+?)","errorType":"error_code","errorClass":"AwsException","httpStatus":400,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/applicationautoscaling/ApplicationAutoScalingService.java","lineNumber":189,"sourceCode":"        String prefix = region + \"::\" + serviceNamespace + \"::\";\n        return targets.scan(k -> k.startsWith(prefix)).stream()\n                .filter(t -> resourceIds == null || resourceIds.isEmpty() || resourceIds.contains(t.getResourceId()))\n                .filter(t -> scalableDimension == null || scalableDimension.equals(t.getScalableDimension()))\n                .sorted(Comparator.comparing(ScalableTarget::getResourceId)\n                        .thenComparing(ScalableTarget::getScalableDimension))\n                .toList();\n    }\n\n    /**\n     * Deregisters a scalable target and, per AWS semantics, deletes every scaling policy\n     * attached to it along with the CloudWatch alarms those policies own.\n     */\n    public void deregisterScalableTarget(String serviceNamespace, String resourceId,\n                                         String scalableDimension, String region) {\n        validateTriple(serviceNamespace, resourceId, scalableDimension);\n        String key = targetKey(region, serviceNamespace, resourceId, scalableDimension);\n        if (targets.get(key).isEmpty()) {\n            throw new AwsException(\"ObjectNotFoundException\",\n                    \"No scalable target found for service namespace: \" + serviceNamespace\n                            + \", resource ID: \" + resourceId\n                            + \", scalable dimension: \" + scalableDimension, 400);\n        }\n        for (ScalingPolicy policy : findPolicies(region, serviceNamespace, resourceId, scalableDimension)) {\n            deleteAlarms(policy, region);\n            policies.delete(policyKey(region, serviceNamespace, resourceId, scalableDimension, policy.getPolicyName()));\n        }\n        targets.delete(key);\n        LOG.infov(\"DeregisterScalableTarget: {0} {1} {2} in {3}\",\n                serviceNamespace, resourceId, scalableDimension, region);\n    }\n\n    // ---------------------------------------------------------------- scaling policies\n\n    public ScalingPolicy putScalingPolicy(String policyName, String policyType, String serviceNamespace,\n                                          String resourceId, String scalableDimension,\n                                          TargetTrackingConfiguration targetTracking,","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/applicationautoscaling/ApplicationAutoScalingService.java#L171-L207","documentation":"Thrown by DeregisterScalableTarget when no target exists for the exact (namespace, resourceId, dimension) triple in that region. Per AWS semantics mirrored here, deregistration also deletes attached scaling policies and their CloudWatch alarms — but only after the existence check passes. Note the code uses HTTP 400 with code ObjectNotFoundException, which matches AWS's Application Auto Scaling behavior of signaling object-not-found as a 400-class ValidationException-family error rather than 404.","triggerScenarios":"Calling DeregisterScalableTarget for a target already deregistered, a resourceId with a typo or different casing (e.g. 'table/MyTable' vs 'table/mytable'), a dimension string mismatch (service prefix differences like 'dynamodb:table:...' vs 'dynamoDB:table:...'), or the wrong region. Any of these make the key lookup miss.","commonSituations":"Cleanup scripts run twice. Drift between regions (target registered in us-east-1, cleanup pointed at us-west-2). Resource ids rebuilt by string concat with subtle differences from what was registered. Tests that deregister in teardown but never registered in setup.","solutions":["Describe first and deregister only on hit: DescribeScalableTargets with the same triple, then DeregisterScalableTarget if a target is returned.","Verify resourceId and dimension byte-for-byte against the original RegisterScalableTarget call (check casing and the service prefix).","Confirm the region of the call matches the region where the target was registered.","In teardown code, treat ObjectNotFoundException as the benign 'already gone' outcome and continue."],"exampleFix":"// before\nclient.deregisterScalableTarget(DeregisterScalableTargetRequest.builder()\n    .serviceNamespace(ns).resourceId(rid).scalableDimension(dim).build());\n\n// after\nboolean exists = !client.describeScalableTargets(DescribeScalableTargetsRequest.builder()\n        .serviceNamespace(ns).resourceIds(rid).scalableDimension(dim).build()\n        .scalableTargets().isEmpty();\nif (exists) {\n    client.deregisterScalableTarget(DeregisterScalableTargetRequest.builder()\n        .serviceNamespace(ns).resourceId(rid).scalableDimension(dim).build());\n}","handlingStrategy":"try-catch","validationCode":"// Existence gate before deregister\nboolean exists = !client.describeScalableTargets(DescribeScalableTargetsRequest.builder()\n        .serviceNamespace(ns).resourceIds(rid).scalableDimension(dim).build()\n        .scalableTargets().isEmpty();\nif (exists) {\n    client.deregisterScalableTarget(DeregisterScalableTargetRequest.builder()\n        .serviceNamespace(ns).resourceId(rid).scalableDimension(dim).build());\n}","typeGuard":null,"tryCatchPattern":"catch (AwsException e) {\n    if (\"ObjectNotFoundException\".equals(e.getCode())) {\n        // already gone — benign for cleanup flows\n        log.debug(\"Scalable target already deregistered: {} {} {}\", ns, rid, dim);\n        return;\n    }\n    throw e;\n}","preventionTips":["Make teardown idempotent: swallow ObjectNotFoundException on deregister.","Reuse the exact resourceId/dimension strings from the register call (verify casing).","Confirm the region matches where the target was registered."],"tags":["application-autoscaling","scalable-target","not-found","cleanup"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}