Documentation

TestNod documentation

Learn how to set up TestNod and configure it to help you spot flaky tests, catch regressions, and see how performance changes over time.

Troubleshooting JUnit XML test result uploads

When a JUnit XML upload to TestNod does not behave the way you expect, work the list below from top to bottom. Each section starts with the symptom and gives the most common cause first.

I get a 404 from the upload endpoint

The response body says "Project not found." This always means the Project-Token header did not match a project. Check, in order:

  1. Is the secret set in CI? This is the most common cause. Most providers do not raise an error when a referenced secret is missing, and instead substitute an empty string. Print a redacted check in your CI step (echo "${TESTNOD_PROJECT_TOKEN:0:6}...") to confirm the variable is present.
  2. Is it the right project's token? Each project has its own token. If you recently rotated the token, make sure CI has the new one.
  3. Is the secret available to this job? GitHub Actions does not expose secrets to forks or to jobs running from forks. GitLab CI masks variables but does not pass them to protected branches unless explicitly configured.

I get a 422 from the upload endpoint

Two distinct 422 bodies come from the upload endpoint. Read the error_message:

  • "metadata.build_id is required." means you did not send test_run[metadata][build_id]. The endpoint will not accept an upload without it, so pick whichever CI variable uniquely identifies the build and pass it through.
  • "There was a problem creating this test run." means the token is valid but the request itself was malformed. Check that metadata fields are scalar strings and that tags use tags[][value]=smoke rather than a flat tags=smoke. The JUnit file is not part of this request. It goes to the presigned URL the upload returns, so a missing or misnamed file does not cause this error.

I get a 422 from the finalize endpoint

Two distinct 422 bodies come from the finalize endpoint:

  • "build_id is required." means the build_id form field on the finalize call was missing. Note that finalize takes build_id at the top level, not nested under test_run[metadata].
  • "No uploads received for this test run." means a run exists for that build_id but no upload was attached to it. Either the upload step failed silently (check the 4xx/5xx responses there first) or the upload used a different build_id than finalize did.

My run is stuck in pending

The most common cause is a missing /finalize call. Upload alone does not transition the run, so the finalize call is required to complete it. Check, in order:

  1. Did the finalize step run? Look at your CI log for the POST /integrations/test_runs/finalize call. If it never ran (the previous step exited early, the conditional was wrong, the matrix never converged), call finalize manually with the right build_id. The call is idempotent and safe to retry.
  2. Did finalize use the same build_id as the uploads? Both calls must agree. If they disagree, finalize gets a 404 and the run stays pending.
  3. Are uploads still pending? Open the run page, where each upload shows its state. If any upload is still in pending after a minute or two, contact [email protected] with the test_run_id and the TestNod team will look into it.

The upload returns 201 but no run appears

The response includes a test_run_url. Open it directly. If the page loads but the run is in pending, see "My run is stuck in pending" above. If the page loads but the run is in processing for a long time, see "My run is stuck in processing" below. If the page 404s, the response was likely from a different project than the one you have open in the UI, so double-check which project the token belongs to.

My run is stuck in processing

Wait two minutes, then refresh. If it has not moved:

  1. Check the size of the XML. Files larger than a few hundred MB take longer to parse.
  2. Check the file is valid XML. Run it through xmllint --noout report.xml locally.
  3. Check that the file is actually JUnit XML. Some CI dialects produce a wrapper format (Allure, ReportPortal native) that is not JUnit XML even if the file extension says .xml.
  4. If none of the above explain it, the run will move to failed shortly with a stored failure message.

My run finished but a test I expected is missing

The case identity is (classname, name). If either changes between runs, TestNod treats it as a different case. Check the raw XML for the case on a passing run vs. a failing run and compare both attributes character-for-character.

I'm getting parse errors I cannot diagnose

Every upload stores exactly what your CI client sent in an internal submission_params field (request headers, including your project token, are not captured). Email [email protected] with your project's public ID and the run's public ID, and the TestNod team will look at the stored payload.

Be first to try TestNod

We're opening early access soon. Drop your email and we'll get you in, and we're happy to help you set up too.

No spam. We'll only email you about TestNod.