apache/druid · info

Requested delete of lookup

Error message

Requested delete of lookup [%s]/[%s] but lookup does not exist!

What it means

LookupCoordinatorManager.deleteLookup() logs this warning and returns false when the tier exists but the named lookup is not in it (priorTierSpec.containsKey(lookup) is false). The delete is a no-op and the config is left unchanged.

Solutions

  1. List lookups in the tier via GET /druid/coordinator/v1/lookups/{tier} to confirm the exact name.
  2. Treat the false return as idempotent success if the desired end state is 'lookup absent'.
  3. Fix the lookup name (case-sensitive) in the client.
  4. Guard automation against double-deletes by checking existence first or tolerating the false return.

Example fix

// before
manager.deleteLookup("__default", "Country"); // wrong case
// after
manager.deleteLookup("__default", "country");
Defensive patterns

Strategy: validation

Validate before calling

Map<String, Map<String, Object>> config = coordinatorManager.getKnownLookups();
boolean exists = config != null
    && config.getOrDefault(tier, Collections.emptyMap()).containsKey(lookup);
if (!exists) { /* lookup absent: skip or treat as success */ }

Prevention

When it happens

Trigger: deleteLookup(tier, lookup) is called with a lookup name not present in the tier's lookup map — typo, already-deleted lookup, or lookup configured under a different tier.

Common situations: Repeated DELETE calls after the lookup was already removed; automation scripts using stale lookup names; case-sensitivity mismatches in lookup names.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/d3608163127f6e7a. Report an issue: GitHub.

Appendix: source

Thrown at server/src/main/java/org/apache/druid/server/lookup/cache/LookupCoordinatorManager.java:295

  public boolean deleteLookup(final String tier, final String lookup, AuditInfo auditInfo)
  {
    Preconditions.checkState(lifecycleLock.awaitStarted(5, TimeUnit.SECONDS), "not started");

    synchronized (this) {
      final Map<String, Map<String, LookupExtractorFactoryMapContainer>> priorSpec = getKnownLookups();
      if (priorSpec == null) {
        LOG.warn("Requested delete lookup [%s]/[%s]. But no lookups exist!", tier, lookup);
        return false;
      }
      final Map<String, Map<String, LookupExtractorFactoryMapContainer>> updateSpec = new HashMap<>(priorSpec);
      final Map<String, LookupExtractorFactoryMapContainer> priorTierSpec = updateSpec.get(tier);
      if (priorTierSpec == null) {
        LOG.warn("Requested delete of lookup [%s]/[%s] but tier does not exist!", tier, lookup);
        return false;
      }

      if (!priorTierSpec.containsKey(lookup)) {
        LOG.warn("Requested delete of lookup [%s]/[%s] but lookup does not exist!", tier, lookup);
        return false;
      }

      final Map<String, LookupExtractorFactoryMapContainer> updateTierSpec = new HashMap<>(priorTierSpec);
      updateTierSpec.remove(lookup);

      if (updateTierSpec.isEmpty()) {
        updateSpec.remove(tier);
      } else {
        updateSpec.put(tier, updateTierSpec);
      }
      return configManager.set(LOOKUP_CONFIG_KEY, updateSpec, auditInfo).isOk();
    }
  }

  public Set<String> discoverTiers()
  {
    Preconditions.checkState(lifecycleLock.awaitStarted(5, TimeUnit.SECONDS), "not started");

View on GitHub (pinned to 9b90983fd2)