floci-io/floci · error · AwsException

ResourceInUse

ResourceInUse

Error message

The namespace contains existing services and cannot be deleted.

What it means

A Cloud Map namespace cannot be deleted while any service still references it. Floci's deleteNamespace scans the service store for services whose namespaceId equals the namespace id and throws ResourceInUse (HTTP 400) when at least one is found. AWS returns the same error; deletion is a no-op until all services in the namespace are deleted first.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudmap/CloudMapService.java:149

        return requireNamespace(id);
    }

    public List<Namespace> listNamespaces(String region) {
        List<Namespace> result = new ArrayList<>();
        for (Namespace n : scan(namespaceStore)) {
            if (region.equals(n.getRegion())) {
                result.add(n);
            }
        }
        return result;
    }

    public Operation deleteNamespace(String id, String region) {
        Namespace ns = requireNamespace(id);
        boolean hasServices = scan(serviceStore).stream()
                .anyMatch(s -> ns.getId().equals(s.getNamespaceId()));
        if (hasServices) {
            throw new AwsException("ResourceInUse",
                    "The namespace contains existing services and cannot be deleted.", 400);
        }
        namespaceStore.delete(id);
        return submitOperation("DELETE_NAMESPACE", "NAMESPACE", id, region);
    }

    // ──────────────────────────── Services ────────────────────────────

    public Service createService(String name, String namespaceId, String creatorRequestId,
                                 String description, String dnsConfig, String healthCheckConfig,
                                 String healthCheckCustomConfig, String type,
                                 Map<String, String> tags, String region) {
        if (name == null || name.isBlank()) {
            throw new AwsException("InvalidInput", "Service name is required.", 400);
        }
        String resolvedNamespaceId = namespaceId;
        if (dnsConfig != null && resolvedNamespaceId == null) {
            // DnsConfig may carry the namespace id when the top-level field is absent.

View on GitHub (pinned to 62ff490619)

Solutions

  1. List services with ListServices (namespace-scoped) and DeleteService each one, waiting for the delete operations to succeed, before DeleteNamespace
  2. Make teardown order explicit: services first, then namespace
  3. Catch ResourceInUse and retry after the pending service deletions complete

Example fix

// before
cloudMapClient.deleteNamespace(r -> r.id(namespaceId));

// after
cloudMapClient.listServices(r -> r.namespaceId ? null : null); // enumerate
List<ServiceSummary> services = new ArrayList<>();
String nextToken = null;
do {
    final String token = nextToken;
    ListServicesResponse page = cloudMapClient.listServices(r -> {
        if (token != null) r.nextToken(token);
    });
    services.addAll(page.services());
    nextToken = page.nextToken();
} while (nextToken != null);
for (ServiceSummary s : services) {
    if (namespaceId.equals(s.namespaceId())) {
        cloudMapClient.deleteService(r -> r.id(s.id()));
    }
}
cloudMapClient.deleteNamespace(r -> r.id(namespaceId));
Defensive patterns

Strategy: validation

Validate before calling

boolean hasServices = cloudMapClient.listServices Paginator.stream(r -> r)
    .flatMap(p -> p.services().stream())
    .anyMatch(s -> namespaceId.equals(s.namespaceId()));
if (hasServices) {
    // delete each service (and wait for the delete operation) before DeleteNamespace
}

Try / catch

try {
    cloudMapClient.deleteNamespace(r -> r.id(namespaceId));
} catch (ServiceDiscoveryException e) {
    if ("ResourceInUse".equals(e.awsErrorDetails().errorCode())) {
        // delete remaining services, wait for their operations, then retry the namespace delete
    } else { throw e; }
}

Prevention

When it happens

Trigger: DeleteNamespace on a namespace that contains services created via CreateService. Typical in teardown scripts that delete the namespace without enumerating and deleting its services, or when a service creation raced the delete.

Common situations: Environment teardown ordering bugs (namespace deleted before its services); test cleanup between runs; a service created asynchronously by another process just before deletion.

Related errors


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