Troubleshooting CI/CD Integration

Intermediate 15 minutes DevOps / Platform Engineers Advanced Configuration

Diagnose common Chainsaw CI/CD failures — authentication 401/400 errors, org-slug URL mistakes, and policy-block 403 verdicts — using the CHW error codes Chainsaw returns.

Overview

When a CI/CD job fails against Chainsaw, the response body carries a stable CHW-NNNN code in error.code and a docs URL. Read that code first — it tells you whether the failure is authentication, a malformed URL, or an intentional policy block. This page maps the failures you are most likely to hit from a pipeline to the codes Chainsaw actually returns.

Every Chainsaw error response looks like this — grab the code before guessing:

{
  "error": {
    "code": "CHW-2001",
    "message": "request blocked by configured policy",
    "docs": "https://docs.chain305.com/errors/CHW-2001"
  }
}

Authentication failures (HTTP 401)

npm ships installs with no Authorization header

Symptom. npm ci fails and the proxy returns HTTP 401, even though the secrets are set.

Cause. The .npmrc _auth field expects the base64-encoded CLIENT_ID:CLIENT_SECRET. Passing the raw CLIENT_ID:CLIENT_SECRET literal makes npm ship installs with no Authorization header, and the proxy rejects the request.

Fix. Generate the token with printf '%s' "$CLIENT_ID:$CLIENT_SECRET" | base64 and keep always-auth=true so the credential rides on tarball fetches, not just metadata lookups. This is the pattern used in the combined CI guide.

Missing or empty credential

A request with no valid token returns CHW-1001 (no valid session or token) — the Authorization header was missing or empty. In CI this usually means the secret was never injected into the job (typo in the secret name, or the step is missing the env:/withCredentials block). Confirm the secret is present in the job environment before debugging the proxy.

Expired or revoked service token

CHW-1002 (token expired or revoked) means the credential itself is no longer valid. If you rotate service tokens on a schedule, a pipeline pinned to the old secret will start failing with this code — update the CI secret store with the new token. See How to Create and Manage Client Credentials.

Configuration / URL failures (HTTP 400)

Legacy non-org-scoped URL

Symptom. Requests fail with HTTP 400 and CHW-4314 (OrgSlugRequired).

Cause. The instance has CHAINSAW_REQUIRE_ORG_SLUG=true and the client used the legacy /repository/{repo}/... shape with no org slug.

Fix. Use the org-scoped form /repository/@{org-slug}/{repo}/.... New single-tenant installs default to org slug default; confirm yours under Settings → Organization → Slug, or copy it from the @<slug> segment of any generated config snippet. All the examples in the combined guide use /repository/@default/....

Unparseable repository path

CHW-4307 (InvalidRepositoryPath) (HTTP 400) means the /repository/... path was missing the repo name or path segment — for example a Docker pull written as <host>/<image> instead of <host>/repository/@{org-slug}/docker/.... Recheck the registry URL in the generated config against the per-ecosystem reference in How to Configure Your Package Manager to Use Chainsaw.

pip trusted-host rejected

When you use a pip.conf/pip.ini, trusted-host takes a bare hostname (optionally host:port). Appending a path (e.g. <host>/chainsaw) makes pip reject the configuration — the path belongs in index-url only.

Reverse-proxy base path

If you front Chainsaw with a reverse proxy that adds a base path (e.g. /chainsaw), prepend that segment to every URL and keep it consistent with NEXT_APP_BASEPATH in your .env. A mismatch here surfaces as 400/404 routing errors that look like auth failures but are not.

Policy blocks (HTTP 403) — working as intended

A 403 from a policy block is Chainsaw doing its job: the package was denied and the install command exits non-zero, failing the build. These are not bugs to work around — review the matched policy in the audit log and remediate the package or request an exception.

CodeMeaningFirst action
CHW-2001Request blocked by a configured policy (age-gate, origin, signature, etc.)Review the matching policy in the audit log; remediate the signal or ask a policy admin
CHW-2002Package blocked — known vulnerability at/above the severity floorUpgrade to a patched version, or add a vulnerability exception
CHW-2003Package blocked — license not on the repository allow-listAdd the SPDX ID to the allow-list, or pick a compatibly-licensed package
CHW-2004Suspected typosquat (small edit distance to a popular name)Verify the intended name; allowlist the coordinate if legitimate
CHW-2302Download blocked by the policy engineReview the matched policy in the audit log; request an exception
CHW-2303Package flagged as known malicious by the supply-chain scannerVerify the coordinate, audit the lockfile, report if a false positive
CHW-2304Blocked by a repository hook (custom scanner/webhook returned block=true)Review the hook response body and the hook configuration
CHW-1802Package version quarantined by an admin (blocking mode on)Contact the admin who quarantined it; ask them to remove a stale quarantine
For a deny that should be allowed in a specific pipeline, scope an exception to that pipeline’s service token rather than weakening the global policy. See How to Manage Policy Precedence and Exception Workflows.

Packages bypassing the firewall entirely

If a build succeeds but the Traffic page shows no requests for that ecosystem, packages are being served from a local cache and never reach Chainsaw. This is a caching problem, not an error code:

  • Clear local caches on the first Chainsaw run (rm -rf node_modules, ~/.m2/repository, ~/.gradle/caches; pip cache purge; docker image prune -a, etc.).
  • Rotate the CI dependency cache key once during onboarding so packages cached before Chainsaw was configured are re-fetched through the firewall.
  • On persistent Jenkins workspaces, also clear the workspace or rotate the agent.

Each ecosystem’s cache-clear commands are listed in How to Configure Your Package Manager to Use Chainsaw.

Verifying the fix

After changing config, confirm requests are actually flowing through the proxy:

  1. Open Traffic in the Chainsaw dashboard.
  2. Filter by the service token’s Client ID.
  3. Confirm requests use the expected repository and outcome (allow vs. block).

Next Steps