apache/druid · info

Requested delete of lookup

Error message

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

What it means

LookupCoordinatorManager.deleteLookup() logs this warning and returns false when the lookup config exists but the requested tier does not, so there is no tier map to remove the lookup from. No configuration change is persisted.

Solutions

  1. Fetch GET /druid/coordinator/v1/lookups/config and verify the tier name exactly.
  2. Treat the false return as idempotent success when the target tier is expected to be gone.
  3. Correct the tier name in the calling client or job config.
  4. Check you are calling the intended cluster's coordinator (config/URL mismatch is common).

Example fix

// before
manager.deleteLookup("prod_tier", "country");
// after
manager.deleteLookup("__default", "country"); // tier that actually exists
Defensive patterns

Strategy: validation

Validate before calling

Map<String, Map<String, Object>> config = coordinatorManager.getKnownLookups();
if (config == null || !config.containsKey(tier)) { /* tier missing: skip or correct the tier name */ }

Prevention

When it happens

Trigger: deleteLookup(tier, lookup) runs with a tier name absent from the known-lookups map (priorTierSpec == null) — wrong tier name or tier previously deleted.

Common situations: DELETE /druid/coordinator/v1/lookups/{tier}/{lookup} with a misspelled tier; environments where lookups live under a different tier name (e.g., __default vs custom); multi-cluster tooling pointed at the wrong cluster.

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/248903977d3c9499. Report an issue: GitHub.

Appendix: source

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

      return configManager.set(LOOKUP_CONFIG_KEY, updateSpec, auditInfo).isOk();
    }
  }

  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();
    }

View on GitHub (pinned to 9b90983fd2)