Web API /api/issues/search?resolutions=A,B,C silently returns total=0 for valid values (CE 26.4)

Web API /api/issues/search returns total=0 for valid multi-comma resolutions= filter (CE 26.4)

Must-share information

  • Which versions are you using:
    • SonarQube Server 26.4.0.121862 Community Build
    • MQR (Multi-Quality Rule) mode enabled
    • Deployment: official Docker image sonarqube:community
    • Database: PostgreSQL 15
  • What are you trying to achieve:
    Query issues filtered by multiple resolution values via
    /api/issues/search?resolutions=A,B,C (e.g. to count all issues that
    were triaged as either FALSE-POSITIVE, ACCEPTED, or WONTFIX in
    one round trip).
  • What have you tried so far:
    • Confirmed via curl that single-value resolutions=FALSE-POSITIVE
      works as documented.
    • Confirmed that any multi-value resolutions=A,B[,C…] form returns
      total=0, regardless of value order or which value the issue’s
      actual resolution field matches.
    • Other comma-separated list parameters on the same endpoint
      (statuses=, types=, severities=, impactSeverities=) work as
      expected on the same instance.
    • Reproducible 100% on a fresh project after a clean scan and a
      single do_transition call.

Bug summary

The Web API endpoint /api/issues/search documents resolutions as a
comma-separated list of resolution values. In SonarQube Community Build
26.4 (MQR mode), passing more than one value through this parameter
silently returns total=0 and issues=[], even when matching issues
clearly exist (verified by querying with the same single value, by
querying without the filter, and by reading the resolution field of
the issue object directly).

The single-value form works. The multi-value form does not. There is no
HTTP error, no warning in the response payload, and no entry in
sonar.log — the result is a silent zero-result, which makes this
particularly painful for automation and CI pipelines.

Steps to reproduce

Setup

TOKEN="squ_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
URL="https://your-sonarqube.example.com"
PROJECT="your-project-key"

Step 1 — find one open VULNERABILITY issue and mark it FALSE-POSITIVE

KEY=$(curl -sf -u "$TOKEN:" \
  "$URL/api/issues/search?componentKeys=$PROJECT&types=VULNERABILITY&statuses=OPEN&ps=1" \
  | python3 -c 'import sys,json;d=json.load(sys.stdin);print(d["issues"][0]["key"])')

curl -sf -u "$TOKEN:" -X POST \
  "$URL/api/issues/do_transition" \
  -d "issue=$KEY&transition=falsepositive"

Step 2 — single-resolution query (works :white_check_mark:)

curl -sf -u "$TOKEN:" \
  "$URL/api/issues/search?issues=$KEY&resolutions=FALSE-POSITIVE&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'
  • Expected: 1
  • Actual: 1 — works as documented.

Step 3 — multi-comma resolutions query (broken :cross_mark:)

curl -sf -u "$TOKEN:" \
  "$URL/api/issues/search?issues=$KEY&resolutions=FALSE-POSITIVE,ACCEPTED,WONTFIX,FIXED&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'
  • Expected: 1 (the issue’s resolution=FALSE-POSITIVE matches the
    first value of the requested list).
  • Actual: 0 — the bug.

Step 4 — ordering and combinations don’t help

# Matching value first:
curl -sf -u "$TOKEN:" "$URL/api/issues/search?issues=$KEY&resolutions=FALSE-POSITIVE,ACCEPTED&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'

# Matching value second:
curl -sf -u "$TOKEN:" "$URL/api/issues/search?issues=$KEY&resolutions=ACCEPTED,FALSE-POSITIVE&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'

# Hyphen-free values only (ACCEPTED,WONTFIX) — no FALSE-POSITIVE in the list:
curl -sf -u "$TOKEN:" "$URL/api/issues/search?issues=$KEY&resolutions=ACCEPTED,WONTFIX&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'

# resolved=true without resolutions= (sanity check):
curl -sf -u "$TOKEN:" "$URL/api/issues/search?issues=$KEY&resolved=true&ps=1" \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])'
  • Actual:
    • 0 — multi-comma broken regardless of order.
    • 0 — multi-comma broken regardless of order.
    • 0 — multi-comma broken even when no value contains a hyphen
      (so this is not a hyphen-parsing issue around FALSE-POSITIVE).
    • 1resolved=true (without resolutions=) works as expected.

Expected behaviour

resolutions=A,B,C should match the union of issues whose resolution
field equals any of A, B, or C. This matches the behaviour of all
other comma-separated list parameters on the same endpoint
(statuses=, types=, severities=, impactSeverities=) and the
documented contract in the Web API specification.

Actual behaviour

resolutions=A,B,C returns total=0 and issues=[]. No HTTP error,
no warning, no log entry. Single-value resolutions=A returns the
matching issue correctly.

Workarounds

Three patterns we use in our automation while waiting for a fix:

  1. Iterate per resolution and sum client-side:

    total=0
    for r in WONTFIX ACCEPTED FALSE-POSITIVE; do
      n=$(curl -sf -u "$TOKEN:" \
        "$URL/api/issues/search?componentKeys=$PROJECT&resolutions=$r&ps=1" \
        | python3 -c 'import sys,json;print(json.load(sys.stdin)["total"])')
      total=$((total + n))
    done
    echo "$total"
    
  2. Drop resolutions= filter, use resolved=true and filter
    client-side from the issue object:

    curl -sf -u "$TOKEN:" \
      "$URL/api/issues/search?componentKeys=$PROJECT&resolved=true&ps=200" \
      | python3 -c '
    import sys,json
    d=json.load(sys.stdin)
    wanted={"FALSE-POSITIVE","ACCEPTED","WONTFIX"}
    print(sum(1 for i in d.get("issues",[]) if i.get("resolution","") in wanted))
    '
    
  3. Look up a known issue by key and read the resolution field
    directly:

    curl -sf -u "$TOKEN:" "$URL/api/issues/search?issues=$KEY&ps=1" \
      | python3 -c 'import sys,json;i=json.load(sys.stdin)["issues"];print(i[0].get("resolution","") if i else "")'
    

All three are noticeably more verbose than what the documented
multi-comma form should provide.

Severity / impact

Medium. No data corruption, no security impact, but:

  • Silent failure: a script using resolutions=A,B,C looks like it ran
    successfully, just with zero matches. There is no signal for callers
    to detect the misbehaviour.
  • Affects any automation, CI pipeline, or dashboard that aggregates
    triaged issues across multiple resolution states — a common pattern
    for governance reporting.
  • The documented API contract is broken, which makes the Web API less
    trustworthy for consumers writing new integrations.

Additional information

  • Reproducible: 100% on the affected version, immediately after a
    fresh scan and one do_transition call.

  • Single-value form works — confirms the issue exists and is found
    by the resolution filter individually.

  • Other comma-list parameters on the same endpoint work
    statuses=OPEN,REOPENED,CONFIRMED, types=VULNERABILITY,BUG,
    severities=BLOCKER,CRITICAL all return the correct union, on the
    same instance and the same project.

  • Hyphen is not the cause — the bug also affects all-uppercase
    hyphen-free combinations such as resolutions=ACCEPTED,WONTFIX.

  • No sonar.log output when issuing the broken query at INFO
    level. Did not test at DEBUG/TRACE, happy to provide if useful.

  • Server / Edition:

    GET /api/server/version → 26.4.0.121862
    GET /api/system/info → Edition: "Community"
    

Happy to provide a HAR capture, raw response payloads, or a minimal
reproduction project if that would help triage. Thanks!

Hi,

I just did some testing on Next, our dogfooding server, and it a multi-status search worked fine through the UI. Checking the developer tools, I see not a comma-delimited search, but a %2C-delimited search.

When in doubt, I always start from the UI.

 
HTH,
Ann