SonarSource/sonarqube · error · NotFoundException

Analysis ' ' not found

Error message

Analysis '%s' not found

What it means

api/project_analyses/delete cannot find the requested analysis (snapshot) by uuid, or the snapshot exists but has UNPROCESSED status, which is treated as not-found. DeleteAction.selects the snapshot by uuid and throws analysisNotFoundException('Analysis %s not found') in both cases.

Solutions

  1. Re-fetch the analysis uuid via api/project_analyses/search?project=<key> and use a current uuid.
  2. Wait until the analysis finishes processing (status becomes PROCESSED) before deleting.
  3. Make the deletion idempotent: treat 404 as success in cleanup scripts.
  4. Verify you are calling the right SonarQube instance/environment where the analysis exists.

Example fix

// before
deleteAnalysis('AXh3kQ9exampleUuid');   // already deleted
// after
const analyses = await get(`/api/project_analyses/search?project=${key}`);
for (const a of analyses.analyses) {
  if (a.status === 'PROCESSED' && !a.last) await deleteAnalysis(a.key);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// always resolve a fresh uuid before deleting
const search = await get(`/api/project_analyses/search?project=${encodeURIComponent(key)}`);
const target = search.analyses.find(a => a.key === analysisUuid);
if (!target) throw new Error(`Analysis ${analysisUuid} no longer exists`);
if (target.status !== 'PROCESSED') throw new Error('Analysis still processing; retry later');
if (target.last) throw new Error('Refusing to delete the last analysis');

Type guard

function isDeletableAnalysis(a) {
  return Boolean(a) && a.status === 'PROCESSED' && a.last === false;
}

Try / catch

try {
  await deleteAnalysis(uuid);
} catch (e) {
  if (isNotFound(e, /Analysis .* not found/)) {
    log.info(`Analysis ${uuid} already gone; treating as deleted`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: DELETE api/project_analyses/delete with a PARAM_ANALYSIS uuid that does not exist, was already deleted, or refers to an analysis still in UNPROCESSED (in-progress) status.

Common situations: Retention scripts replaying a delete for an already-deleted analysis; hardcoded uuid copied from an old log; calling delete while an analysis is still being processed on the compute engine.

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

Appendix: source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/projectanalysis/ws/DeleteAction.java:74

      .setSince("6.3")
      .setPost(true)
      .setHandler(this);

    action.createParam(PARAM_ANALYSIS)
      .setDescription("Analysis key")
      .setExampleValue(Uuids.UUID_EXAMPLE_04)
      .setRequired(true);
  }

  @Override
  public void handle(Request request, Response response) throws Exception {
    String analysisUuid = request.mandatoryParam(PARAM_ANALYSIS);

    try (DbSession dbSession = dbClient.openSession(false)) {
      SnapshotDto analysis = dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid)
        .orElseThrow(() -> analysisNotFoundException(analysisUuid));
      if (STATUS_UNPROCESSED.equals(analysis.getStatus())) {
        throw analysisNotFoundException(analysisUuid);
      }
      userSession.checkComponentUuidPermission(ProjectPermission.ADMIN, analysis.getRootComponentUuid());

      checkArgument(!analysis.getLast(), "The last analysis '%s' cannot be deleted", analysisUuid);
      checkNotUsedInNewCodePeriod(dbSession, analysis);

      analysis.setStatus(STATUS_UNPROCESSED);
      dbClient.snapshotDao().update(dbSession, analysis);
      dbSession.commit();
    }
    response.noContent();
  }

  private void checkNotUsedInNewCodePeriod(DbSession dbSession, SnapshotDto analysis) {
    boolean isSetAsBaseline = dbClient.newCodePeriodDao().existsByProjectAnalysisUuid(dbSession, analysis.getUuid());
    checkArgument(!isSetAsBaseline,
      "The analysis '%s' can not be deleted because it is set as a new code period baseline", analysis.getUuid());

View on GitHub (pinned to 184c821202)