Troubleshooting
Common issues, what they mean, and how to fix them. If something isn’t covered here, ping us via the contact channels at the bottom of the page.HMAC errors
Before debugging, run the handshake test. Click Test connection in your provider dashboard (
POST /providers/id/:id/hmac/test), or npx shadowfeed verify --endpoint <url> --secret <secret> if you use the SDK. It signs and probes your endpoint exactly like a real buyer and tells you the precise stage that failed — usually faster than reading logs.401 invalid HMAC signature on every request
Two causes, equally common: secret mismatch, or path mismatch. Check both. Secret mismatch — same secret on both sides?Check the env var name on your server
From the dashboard → View setup guide → the placeholder env var line shows the name your server expects (
SHADOWFEED_PARTNER_SECRET).Verify it's set
On your server:
echo $SHADOWFEED_PARTNER_SECRET (or your platform’s equivalent — Worker secret, Vercel env, etc.).source_path (relative to partner_endpoint). If your verifier builds the canonical string from new URL(req.url).pathname and your app is mounted behind a prefix (common with x402 routers) or your partner_endpoint includes a path, the two PATHs differ and the signature can never match.
- Confirm
partner_endpointis origin-only (https://api.you.com, no path, no trailing slash). - If your router is mounted under a prefix (
/api,/x402, …), strip it before signing — see HMAC Integration → Mounted behind a prefix. - The SDK adapters handle this automatically.
ShadowFeed can’t reach my route — 404 or “route exists?”
Cause: ShadowFeed callspartner_endpoint + source_path literally. A 404 means that combined URL doesn’t resolve to a real route on your server — your signature code never even runs. This is a silent killer: you’re watching for 401s that never arrive while every call 404s.
Fix:
- Register
partner_endpointas origin-only andsource_pathas the exact path your server already serves (e.g. your existing x402 route). - A stale
/v1or duplicated segment is the usual culprit —partner_endpoint = https://api.you.com/v1andsource_path = /v1/whalesproduces…/v1/v1/whales. - Run Test connection — the response echoes
probed_pathand the upstream HTTP status so you can see exactly what ShadowFeed hit.
Buyers pay STX but I earn nothing (my logs show a 402 to ShadowFeed)
Cause: you already gate this endpoint with x402 (Solana/EVM), and the HMAC bypass didn’t fire — so the ShadowFeed call fell through to your paywall, which answered402. ShadowFeed treats any non-2xx upstream response as a failed delivery: no revenue is credited and the agent gets an error, even though they paid STX.
Fix:
- Mount the HMAC verifier before your x402 middleware, and set your
skipX402flag on a valid signature. - The underlying reason the bypass failed is almost always a secret or path mismatch — fix that (sections above) and the 402s turn into 200s. See Coexisting with your existing x402 paywall.
Some calls succeed, some return 401
Likely cause: clock drift > 5 minutes between your server and ShadowFeed.- Linux: enable systemd-timesyncd or ntpd
- Cloud platforms (Cloudflare Workers, Vercel, Render, Railway) sync time automatically — if you’re on one of these and seeing drift, something else is wrong
401 on POST requests but GET works
Cause: middleware reads the body to verify HMAC, then it’s already consumed when the route handler runs (or vice versa).| Stack | Fix |
|---|---|
| TypeScript / Fetch API | Use req.clone().text() so original body remains readable |
| Express | Install body-parser, then access req.rawBody |
| FastAPI | Use await request.body() once in middleware, store on request.state |
| Go | Read body in middleware, then r.Body = io.NopCloser(strings.NewReader(...)) |
Worked yesterday, all 401 today
Likely cause: you rotated the secret in the dashboard but didn’t update your server’s env var. Fix: pull the latest secret (or rotate again if you didn’t save it) → redeploy your server with the new value.Replay attack rejection: nonce already used
If your verifier returns this for legitimate requests, your nonce cache is too aggressive or there’s a retry happening.The nonce should expire after 5 minutes. Each ShadowFeed request uses a fresh UUID v4. If you’re behind a proxy that retries on timeout, the proxy may be sending the SAME signed request twice — increase your upstream timeout to 30s+.
Onboarding errors
”handle already taken”
Pick a different handle. URLs are unique. Once chosen, the handle is permanent for that provider record.”invalid or reserved handle”
Reserved handles (admin, api, auth, dashboard, system, etc.) are blocked.
- Allowed characters: lowercase letters, numbers, hyphens
- Length: 3-32 chars
- Must start and end with alphanumeric
”partner_endpoint must be https://…”
We only proxy to HTTPS endpoints. Set up TLS on your API (Cloudflare proxy, Let’s Encrypt) or use a managed runtime that handles it (Workers, Vercel, Render).Wizard step 4 didn’t show me the HMAC secret
- If Hosted Mirror mode
- If Partner Bridge mode
There’s no HMAC secret in this mode — we host your data, no signed requests needed.
Withdrawal errors
”no linked withdrawal wallet”
You must link a Stacks wallet before withdrawing. See Withdrawals → Linking a withdrawal wallet.”destination must match your linked withdrawal wallet”
Withdrawals can only go to the wallet you linked. To send elsewhere, re-link with the new address first (signature challenge).”minimum withdrawal is 1 STX”
We have a 1 STX floor to avoid dust transactions. Accumulate more revenue first, or contact us if you have a strong use case for a smaller withdrawal.”insufficient pending balance”
You’re trying to withdraw more than your currentpending_revenue. Check the dashboard — pending balance updates ~immediately after each paid query but may have small lag during high traffic.
Withdrawal stuck in broadcast state
The cron poller checks pending withdrawals every minute. Most Stacks blocks land within 10 minutes.
If after 30+ minutes the status hasn’t changed:
”broadcast failed — funds restored to pending balance”
Your withdrawal was rolled back. Check the error detail (returned in the API response). Common causes:- Platform wallet low on STX (we’ll catch this and resolve)
- Hiro API rate limit (auto-retry will kick in)
- Network glitch (try again)
pending_revenue is back where it was. Just retry.
Feed errors
My feed returns 503 “provider inactive”
Your provider is inpending or paused state.
- pending: you haven’t added a feed yet. Add at least one feed to auto-activate.
- paused: you (or platform admin) manually paused. Click Resume in the dashboard.
Feed returns 503 “feed paused”
You paused this individual feed. Click Resume in the feed list.Feed returns 502 with upstream error
Yourpartner_endpoint returned a 5xx, or wasn’t reachable. Common causes:
- Endpoint URL is wrong (typo, missing path, http vs https)
- Your server is down
- DNS resolution failed
- TLS certificate expired
- Firewall blocking incoming traffic from Cloudflare
In this case, the buyer still paid 0.005 STX, but we don’t credit your revenue counter (you didn’t actually serve data). The platform fee is also waived for these failures.
Hosted mirror feed shows “feed not yet populated”
The cron poller hasn’t fetched your data source yet. Wait up to one poll interval (default 5 minutes). If still empty after 2 intervals:- Check
last_poll_statusin your feed config (visible in dashboard) - Verify the source URL returns valid JSON:
curl https://your-source-url - Check payload size — we cap at 1 MB per feed
Dashboard / SIWS errors
”Connect a Stacks wallet first”
Your wallet provider (Leather or Xverse) isn’t installed or not loaded yet.”signature verification failed”
The signature doesn’t match expected, or the nonce is stale.- Try signing again — Leather sometimes loses focus mid-flow
- If using Xverse, make sure you’re on the latest version
- If persistent: sign out fully → reload → sign back in
Session expired
We auto-clear sessions after 7 days. Sign in again — your provider account and revenue are unchanged.Reach out
If you’re stuck:- DM us on X — @shadow_agents
- Open an issue on GitHub (link in footer)
- Email —
grants@stacksendowment.co(during M2 grant period)
- Your provider handle
- Stack you’re integrating from (TS / Python / Go / etc.)
- Exact error message
- A request ID or timestamp if you have it (we can grep server logs)
What’s next
HMAC Integration Guide
Verifier code in TypeScript, Python, and Go.
Withdrawals & Revenue
How revenue accounting works.