Pact Broker "401 Unauthorized" / could not publish pacts in CI
The pact publish step reached the Pact Broker (or PactFlow) but was rejected with 401. The broker is up; the request carried no valid credentials or token, so the pacts were not published.
What this error means
Publishing fails with "Error publishing ... 401 Unauthorized" or "could not be published", naming the broker URL, while the broker itself responds.
Pact
Publishing 'web-consumer-user-api' pact to https://myorg.pactflow.io ...
Error: could not publish pact - 401 UnauthorizedCommon causes
No broker token was provided to CI
The publish command has no bearer token or basic-auth credentials, or the secret was not exposed to the step, so the broker returns 401.
An expired or wrong token
A rotated or mistyped token authenticates as nobody, and the broker rejects the publish.
How to fix it
Provide the broker token from a secret
- Store the broker or PactFlow token as a CI secret.
- Pass it to the publish command via the token option or env var.
- Re-run so the authenticated publish succeeds.
.github/workflows/ci.yml
pact-broker publish ./pacts \
--broker-base-url https://myorg.pactflow.io \
--broker-token ${{ secrets.PACT_BROKER_TOKEN }} \
--consumer-app-version ${{ github.sha }}Rotate and update an expired token
A persistent 401 will not clear on retry. Issue a fresh token in the broker and update the CI secret.
How to prevent it
- Keep the broker token in CI secrets, never in the repo.
- Set the consumer app version from the commit SHA for traceability.
- Rotate tokens on a schedule and update the secret in one place.
Related guides
Pact "No pacts found" for provider verification in CIFix Pact "No pacts found" in CI - provider verification found no contracts to verify because the consumer nam…
Pact "Verification failed" provider/consumer mismatch in CIFix Pact "Verification failed" in CI - the provider response did not match the consumer contract, so provider…
Schemathesis "1 failed" server error in CIFix Schemathesis "1 failed" with a server_error check in CI - a generated request triggered a 500 from the AP…