SonarSource/sonarqube · error · NotFoundException

There is no metric with key=%s

Error message

There is no metric with key=%s

What it means

QualityGateConditionsUpdater.getNonNullMetric looks up a metric by key in the DB and throws NotFoundException when no metric matches, meaning the requested metric key does not exist on the server. This protects quality-gate conditions from referencing nonexistent metrics.

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java:132

    validateCondition(metric, operator, errorThreshold);
    Collection<QualityGateConditionDto> otherConditions = getConditions(dbSession, condition.getQualityGateUuid())
      .stream()
      .filter(c -> !c.getUuid().equals(condition.getUuid()))
      .toList();
    checkConditionDoesNotExistOnEquivalentMetric(dbSession, otherConditions, metric);
    condition
      .setMetricUuid(metric.getUuid())
      .setMetricKey(metric.getKey())
      .setOperator(operator)
      .setErrorThreshold(errorThreshold);
    dbClient.gateConditionDao().update(condition, dbSession);
    return condition;
  }

  private MetricDto getNonNullMetric(DbSession dbSession, String metricKey) {
    MetricDto metric = dbClient.metricDao().selectByKey(dbSession, metricKey);
    if (metric == null) {
      throw new NotFoundException(format("There is no metric with key=%s", metricKey));
    }
    return metric;
  }

  private Collection<QualityGateConditionDto> getConditions(DbSession dbSession, String qGateUuid) {
    return dbClient.gateConditionDao().selectForQualityGate(dbSession, qGateUuid);
  }

  private void validateCondition(MetricDto metric, String operator, String errorThreshold) {
    List<String> errors = new ArrayList<>();
    validateMetric(metric, errors);
    checkOperator(metric, operator, errors);
    checkErrorThreshold(metric, errorThreshold, errors);
    checkRatingMetric(metric, errorThreshold, errors);
    checkRequest(errors.isEmpty(), errors);
  }

  private static void validateMetric(MetricDto metric, List<String> errors) {

View on GitHub (pinned to 184c821202)

Solutions

  1. List valid metrics with GET api/metrics/search and use an exact key from the response.
  2. Create the missing custom metric (or restore it via configuration-as-code) before adding the condition.
  3. Fix the typo in the metric key in your provisioning script.
  4. Verify the target server actually defines the metric when migrating gate definitions between instances.

Example fix

// before
createCondition(gateId, "new_coverge", "GT", 80); // 404
// after
String key = searchMetrics("new_coverage").stream()
  .map(Metric::getKey)
  .filter(k -> k.equals("new_coverage"))
  .findFirst()
  .orElseThrow(() -> new IllegalStateException("metric not defined on server"));
createCondition(gateId, key, "GT", 80);
Defensive patterns

Strategy: validation

Validate before calling

// before creating a condition, verify the metric key exists
boolean exists = searchMetrics(metricKey) // GET api/metrics/search?q=<key>
  .getMetrics().stream()
  .anyMatch(m -> metricKey.equals(m.getKey()));
if (!exists) throw new IllegalArgumentException("metric key not defined: " + metricKey);

Try / catch

try {
  createCondition(gateId, metricKey, op, threshold);
} catch (SonarQubeClientException e) {
  if (e.getStatus() == 404 && String.valueOf(e.getMessage()).contains("no metric with key")) {
    throw new IllegalStateException("metric " + metricKey + " missing on this SonarQube server", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST api/qualitygates/create_condition or update_condition with a metricKey that is not in the metrics table (typo, custom metric deleted, metric from another SonarQube instance).

Common situations: Configuration-as-code copied between SonarQube servers where a custom metric only exists on one; metric keys renamed/removed in newer SonarQube versions; typos in metric keys like 'new_coverge' vs 'new_coverage'.

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 SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/cd11aa0c6b678c9f. Report an issue: GitHub.