| name | npm-trusted-publishers |
| description | Configure and troubleshoot npm OIDC Trusted Publishing for GitHub Actions. Use when npm publish fails with E404, OIDC errors, or provenance issues. |
npm Trusted Publishers Skill
Comprehensive guide for npm OIDC Trusted Publishing with pre-flight validation, error handling, and troubleshooting.
Root Cause Analysis Pattern
When npm publish fails with E404 Not Found after OIDC provenance signing:
npm notice publish Signed provenance statement with source and build information from GitHub Actions
npm notice publish Provenance statement published to transparency log: https://search.sigstore.dev/?...
npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/@scope/package - Not found
This is NOT a missing package error - the OIDC token was generated and provenance was signed. The E404 means npm's Trusted Publisher configuration doesn't match the workflow claims.
Workflow Filename Mismatch (Most Common)
npm Trusted Publishers verify the OIDC token's workflow claim against the configured workflow filename.
| Scenario | Result |
|---|
npmjs config: release.yml | ✓ OIDC matches |
Actual workflow: release.yml | ✓ Publish succeeds |
npmjs config: release.yml | ✗ OIDC mismatch |
Actual workflow: npm-publish.yml | ✗ E404 error |
Solution: Either:
- Configure Trusted Publisher for
npm-publish.yml (if that's your workflow)
- Publish from
release.yml only (if Trusted Publisher configured for it)
- Configure both workflow filenames (comma-separated or multiple entries)
Pre-Flight Validation Checklist
Before any release, verify Trusted Publisher configuration:
1. Verify npmjs.com Configuration
Go to: https://www.npmjs.com/package/@SCOPE/PACKAGE/settings/trusted-publishers
Check:
- Repository: OWNER/REPO (exact match)
- Workflow filename: WORKFLOW.yml (just filename, no path)
- Environment: optional (must match if set)
2. Verify GitHub Actions Workflow
permissions:
id-token: write
contents: read
jobs:
publish:
environment: npm
3. Verify Workflow Filename Match
WORKFLOW_NAME=$(basename .github/workflows/release.yml)
echo "Workflow: $WORKFLOW_NAME"
4. OIDC Token Debug Step
Add this step before npm publish to verify OIDC token claims:
- name: Debug OIDC token claims
run: |
echo "Requesting OIDC token..."
OIDC_TOKEN=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm" | jq -r '.value')
if [ -z "$OIDC_TOKEN" ] || [ "$OIDC_TOKEN" = "null" ]; then
echo "::error::OIDC token generation failed"
echo "Check: id-token: write permission is set"
exit 1
fi
echo "OIDC token received (first 50 chars): ${OIDC_TOKEN:0:50}..."
echo "$OIDC_TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | jq . 2>/dev/null || \
echo "Could not decode token claims"
Common Error Matrix
See error-matrix.md for the full troubleshooting table.
Configuration Steps
Initial Setup (First-time only)
-
Create package on npm (requires one-time token):
npm login --registry=https://registry.npmjs.org/
npm publish --access public
-
Configure Trusted Publisher:
- Go to:
https://www.npmjs.com/package/@SCOPE/PACKAGE/settings
- Scroll to "Trusted Publishers"
- Click "Add publisher" → "GitHub Actions"
- Configure:
- Repository owner:
OWNER (e.g., d-o-hub)
- Repository name:
REPO (e.g., chaotic_semantic_memory)
- Workflow filename:
release.yml (just the filename!)
- Environment: Leave empty OR set exactly matching workflow
-
Verify configuration:
curl -s https://registry.npmjs.org/@SCOPE/PACKAGE | jq '.versions[-1].provenance'
Workflow Configuration
name: Release
on:
push:
branches: [main]
permissions:
contents: write
id-token: write
jobs:
publish-npm:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Install latest npm
run: npm install -g npm@latest
- name: Verify OIDC token available
run: |
if [ -z "$ACTIONS_ID_TOKEN_REQUEST_TOKEN" ]; then
echo "::error::OIDC not available - check id-token: write permission"
exit 1
fi
echo "OIDC endpoint available"
- name: Publish with provenance
run: |
# Try OIDC first (no token needed)
if npm publish --provenance --access public 2>&1 | tee /tmp/npm-log; then
echo "Published with OIDC Trusted Publishing"
else
# Check if OIDC failed due to Trusted Publisher config
if grep -q "404" /tmp/npm-log; then
echo "::error::OIDC 404 - Trusted Publisher not configured for this workflow"
echo "::error::Configure at: npmjs.com/package/@SCOPE/PACKAGE/settings/trusted-publishers"
echo "Expected workflow: $(basename $GITHUB_WORKFLOW)"
exit 1
fi
# Fallback to NPM_TOKEN if OIDC failed for other reasons
if [ -n "${NODE_AUTH_TOKEN:-}" ]; then
echo "OIDC failed, using NPM_TOKEN fallback"
npm publish --access public
else
echo "::error::OIDC failed and NPM_TOKEN not available"
exit 1
fi
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Recovery from Failed Release
Check Current State
npm view @SCOPE/PACKAGE versions --json
curl -s https://crates.io/api/v1/crates/PACKAGE/versions | jq '.versions[].num'
gh release list
gh api repos/OWNER/REPO/deployments --jq '.[] | select(.environment == "npm") | {id: .id, state: (.statuses_url | @base64)}'
Re-publish Failed Version
If npm publish failed but other registries succeeded:
npm publish --access public
gh workflow run release.yml -f version=0.3.2
References