pinpoint-apm/pinpoint · error · DataIntegrityViolationException

Duplicate service name:

Error message

Duplicate service name: 

What it means

After a DuplicateKeyException from the DAO insert, the code re-checks selectServiceByName; if a row with that name already exists, it rethrows as DataIntegrityViolationException("Duplicate service name: ..."). This distinguishes a genuine name conflict from a duplicate-key caused by something else (e.g. UID collision). The method is @Retryable on DuplicateKeyException, so this explicit rethrow also stops pointless retries.

Source

Thrown at service-module/src/main/java/com/navercorp/pinpoint/service/service/ServiceRegistryServiceImpl.java:45

        this.serviceRegistryDao = Objects.requireNonNull(serviceRegistryDao, "serviceRegistryDao");
        this.serviceUidGenerator = Objects.requireNonNull(serviceUidGenerator, "serviceUidGenerator");
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    @Retryable(retryFor = DuplicateKeyException.class, maxAttempts = 3)
    public Service insertService(String name) {
        StringPrecondition.requireHasLength(name, "name");
        if (Service.wellKnownService(name) != null) {
            throw new IllegalArgumentException("name is well known");
        }

        int uid = serviceUidGenerator.generate().getUid();
        try {
            serviceRegistryDao.insertService(uid, name);
        } catch (DuplicateKeyException e) {
            if (serviceRegistryDao.selectServiceByName(name) != null) {
                throw new DataIntegrityViolationException("Duplicate service name: " + name, e);
            }
            throw e;
        }

        return new Service(name, uid);
    }

    @Override
    @Transactional(readOnly = true)
    public List<String> getServiceNames() {
        return serviceRegistryDao.selectServiceNames();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Service> getServiceList(int limit) {
        List<ServiceEntity> entityList = serviceRegistryDao.selectServiceList(limit);
        return toServices(entityList);

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Check existence first with selectServiceByName and reuse/update the existing service instead of inserting.
  2. Catch DataIntegrityViolationException (or DuplicateKeyException) around insertService and handle the conflict idempotently.
  3. Use a unique name or adopt a create-or-get pattern.

Example fix

// before
serviceRegistryService.insertService(name);
// after
if (serviceRegistryService.selectServiceByName(name) == null) {
    serviceRegistryService.insertService(name);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (serviceRegistryService.selectServiceByName(name) != null) { /* already exists — skip or reuse */ }

Try / catch

try { serviceRegistryService.insertService(name); } catch (DataIntegrityViolationException | DuplicateKeyException e) { /* handle existing-name conflict idempotently */ }

Prevention

When it happens

Trigger: Calling insertService with a name that already exists in the service_registry table (unique-name constraint violation on insert).

Common situations: Two concurrent registrations of the same name; re-running a provisioning script that already created the service; retry after a previous partial failure.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/9e41da5e4fc9171d. Report an issue: GitHub.