floci-io/floci · error · AwsException

ServiceAlreadyExists

ServiceAlreadyExists

Error message

A service named \"{}\" already exists.

What it means

Thrown when CreateService would create a second service with the same name in the same namespace and region. CloudMapService scans the service store for (region, name, namespaceId) equality — namespace id may come from the top-level field or be extracted from DnsConfig — and raises ServiceAlreadyExists before constructing the new service. AWS enforces the same uniqueness: service names are unique within a namespace.

Source

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

                                 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.
            resolvedNamespaceId = dnsConfigNamespaceId(dnsConfig);
        }
        if (resolvedNamespaceId != null) {
            requireNamespace(resolvedNamespaceId);
        }
        final String nsId = resolvedNamespaceId;
        boolean exists = scan(serviceStore).stream()
                .anyMatch(s -> region.equals(s.getRegion()) && name.equals(s.getName())
                        && java.util.Objects.equals(nsId, s.getNamespaceId()));
        if (exists) {
            throw new AwsException("ServiceAlreadyExists",
                    "A service named \"" + name + "\" already exists.", 400);
        }
        Service service = new Service();
        service.setId("srv-" + randomId(20));
        service.setName(name);
        service.setNamespaceId(nsId);
        service.setDescription(description);
        service.setDnsConfig(dnsConfig);
        service.setHealthCheckConfig(healthCheckConfig);
        service.setHealthCheckCustomConfig(healthCheckCustomConfig);
        service.setType(resolveServiceType(type, dnsConfig));
        service.setCreatorRequestId(creatorRequestId != null ? creatorRequestId : UUID.randomUUID().toString());
        service.setCreateDate(Instant.now());
        service.setRegion(region);
        service.setInstanceCount(0);
        service.setRevision(0L);
        if (tags != null) {
            service.setTags(tags);

View on GitHub (pinned to 62ff490619)

Solutions

  1. Before creating, call ListServices filtered by namespace and check whether the name already exists; reuse it instead of creating.
  2. Delete the stale service (DeregisterInstance first, then DeleteService) if it is leftover from a previous run.
  3. Suffix generated names (e.g. orders-service-<env>-<build>) when concurrent runs may collide.
  4. If the collision is unexpected, verify which namespace id the request resolves to — DnsConfig can carry one when the top-level NamespaceId is absent.

Example fix

// before
client.createService(b -> b.name("orders").namespaceId(nsId));

// after
boolean exists = client.listServices(b -> b.namespaceId(nsId)).services().stream()
    .anyMatch(s -> s.name().equals("orders"));
if (!exists) {
    client.createService(b -> b.name("orders").namespaceId(nsId));
}
Defensive patterns

Strategy: validation

Validate before calling

boolean exists = client.listServices(b -> b.namespaceId(nsId)).services().stream()
    .anyMatch(s -> s.name().equals(name));
if (exists) { /* reuse existing service instead of creating */ }

Try / catch

try {
    client.createService(req);
} catch (ServiceAlreadyExistsException e) {
    // adopt the existing service: fetch it and continue
}

Prevention

When it happens

Trigger: Running CreateService twice with the same Name and NamespaceId in the same region; re-running an idempotent-looking deployment script without cleanup; passing a different namespace id casing/format (e.g. id pulled from DnsConfig instead of the top-level field) and expecting it to be a distinct service — the emulator treats a matching resolved namespace id as a collision.

Common situations: CI pipelines that provision Cloud Map services on every run against a persistent Floci storage mode; drift between what a previous run created and what the script assumes; renaming logic that creates-then-deletes and fails halfway.

Related errors


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