{"record":{"id":"4db493e725cb8ed4","repo":"SonarSource/sonarqube","slug":"metric-key-s-not-found","errorCode":null,"errorMessage":"Metric key '%s' not found","messagePattern":"Metric key '(.+?)' not found","errorType":"exception","errorClass":"org.sonar.db.RowNotFoundException","httpStatus":null,"severity":"error","filePath":"server/sonar-db-dao/src/main/java/org/sonar/db/metric/MetricDao.java","lineNumber":49,"sourceCode":"import org.sonar.db.RowNotFoundException;\n\nimport static org.sonar.db.DatabaseUtils.executeLargeInputs;\n\npublic class MetricDao implements Dao {\n\n  @CheckForNull\n  public MetricDto selectByKey(DbSession session, String key) {\n    return mapper(session).selectByKey(key);\n  }\n\n  public List<MetricDto> selectByKeys(final DbSession session, Collection<String> keys) {\n    return executeLargeInputs(keys, mapper(session)::selectByKeys);\n  }\n\n  public MetricDto selectOrFailByKey(DbSession session, String key) {\n    MetricDto metric = selectByKey(session, key);\n    if (metric == null) {\n      throw new RowNotFoundException(String.format(\"Metric key '%s' not found\", key));\n    }\n    return metric;\n  }\n\n  public List<MetricDto> selectAll(DbSession session) {\n    return mapper(session).selectAll();\n  }\n\n  public List<MetricDto> selectEnabled(DbSession session) {\n    return mapper(session).selectAllEnabled(Pagination.all());\n  }\n\n  public List<MetricDto> selectEnabled(DbSession session, int page, int limit) {\n    return mapper(session).selectAllEnabled(Pagination.forPage(page).andSize(limit));\n  }\n\n  public int countEnabled(DbSession session) {\n    return mapper(session).countEnabled();","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-db-dao/src/main/java/org/sonar/db/metric/MetricDao.java#L31-L67","documentation":"MetricDao.selectOrFailByKey throws RowNotFoundException when no metric matches the given key, for callers that require the metric row to exist. selectByKey returns null when absent; this method converts absence into an exception.","triggerScenarios":"Calling selectOrFailByKey with a metric key that is not registered in the METRICS table (custom metric removed, typo, plugin providing the metric not installed, core metric renamed).","commonSituations":"Custom measures referencing a metric whose plugin was uninstalled; typos in metric keys in quality gate/measure code; metrics removed between SonarQube versions; case mismatches.","solutions":["Verify the metric key exists (e.g. via api/metrics/search) and fix typos","Install/reinstall the plugin that defines the custom metric","Use selectByKey and handle null when the metric may legitimately be absent","Handle RowNotFoundException with a clear message naming the missing metric key"],"exampleFix":"// before\nMetricDto metric = metricDao.selectOrFailByKey(dbSession, \"my_custom_metric\");\n// after\nMetricDto metric = metricDao.selectByKey(dbSession, \"my_custom_metric\");\nif (metric == null) {\n  // metric not defined; skip or register it\n}","handlingStrategy":"try-catch","validationCode":"if (key == null || key.isBlank()) {\n  throw new IllegalArgumentException(\"Metric key is required\");\n}\nif (metricDao.selectByKey(dbSession, key) == null) {\n  throw new IllegalArgumentException(\"Metric \" + key + \" is not defined\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  MetricDto metric = metricDao.selectOrFailByKey(dbSession, key);\n} catch (RowNotFoundException e) {\n  // return 404 / skip measure handling\n}","preventionTips":["Prefer selectByKey when the metric may not exist","Verify custom metrics exist after plugin installs/uninstalls","Keep metric keys in constants shared with definitions","Validate metric keys against api/metrics/search in tooling"],"tags":["database","not-found","metrics"],"backgroundTag":"record-not-found","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}