Reference
8 min read
Troubleshooting
Every failure mode documented here includes the exact symptom, diagnosis steps, and fix. If your issue is not listed, check the core concepts page to confirm your mental model, then contact support.
Webhook not receiving events
Symptom
You push a commit to your repo but no sync run appears on the project detail page. The dashboard shows the same last sync time as before.
Diagnosis
- Go to your GitHub repo → Settings → Webhooks. Verify a webhook exists with Payload URL
https://stateanchor.dev/api/webhooks/github. - Click the webhook and check Recent Deliveries. If deliveries show a red X with status 401 or 403, the webhook secret is misconfigured.
- If no deliveries appear at all, the webhook was never triggered. Verify the webhook is set to trigger on push events and the branch matches.
- If deliveries show 200 but no sync run appears, check Trigger.dev for failed jobs (see next section).
Fix
- Wrong URL: Update the Payload URL to exactly
https://stateanchor.dev/api/webhooks/github. No trailing slash. - Secret mismatch: The webhook secret must match the
GITHUB_WEBHOOK_SECRETenvironment variable in Vercel. Regenerate both if unsure. - SSL verification:Ensure SSL verification is enabled (GitHub's default). StateAnchor requires HTTPS.
Sync runs stuck in queued or running
Symptom
A sync run appears on the project detail page but stays in "queued" or "running" status indefinitely. No artifacts are generated and no gate decision is recorded.
Diagnosis
- Check the Trigger.dev dashboard for your project. Look for the sync job -- if it shows as "failed" or "timed out", the error message tells you what went wrong.
- If the job completed in Trigger.dev but the sync run is still "running" in StateAnchor, the completion callback may have failed. Check Vercel function logs for errors on the completion endpoint.
- If multiple sync runs are queued for the same project, Trigger.dev's job deduplication may be preventing the later runs from executing. Only one sync can run per project at a time.
Fix
- Timed out:Sync jobs have a 240-second timeout. If your API spec is very large (>50 endpoints), the generation step may exceed this limit. Reduce the number of output languages or split into multiple specs.
- Job deduplication: Wait for the current sync to complete or fail before triggering another. Pushing rapidly to the same branch creates duplicate webhook events that queue behind the active job.
- Stuck "running":If a sync has been "running" for more than 10 minutes, it is stuck. Trigger a new sync manually from the project detail page -- the new sync will supersede the stuck one.
Gate blocking unexpectedly
Symptom
A sync run completes but the gate decision is "block" when you expected it to pass. Your push was rejected even though you believe the change is non-breaking.
Diagnosis
- Check the gate reason on the sync run detail. It shows exactly which findings triggered the block.
- Identify the lane: ERR findings always block regardless of threshold. WARN findings block only when the count meets or exceeds the configured threshold (default: 0, meaning WARN never blocks).
- Common ERR triggers:
endpoint_removed,field_removed,type_changed,auth_changed,enum_value_removed,oneOf_anyOf_modified. - Common WARN triggers:
required_added(adding a required field to a request body),field_renamed(renaming a field that clients may depend on).
Fix
- Intentional breaking change: Create a drift exception for the specific endpoint and change kind. Exceptions require a named approver and have a maximum 90-day TTL.
- False positive: If a field was never actually used by clients, add a drift exception to acknowledge it. The gate does not know which fields clients use -- it treats all declared fields as contractual.
- Adjust threshold: The default
warn_count_thresholdis already0(WARN never blocks). If you previously raised it and want to relax back to the default, setwarn_count_threshold: 0in your project's policy config. Raise above 0 only when you want WARN to block.
Artifacts not generating
Symptom
A sync run completes successfully with gate_action: proceed, but the artifacts list on the project detail page is empty or missing expected languages.
Diagnosis
- Check the context_snapshot on the sync run. The
validation_resultsfield shows whether each output type passed compilation validation. - If validation failed for a language (e.g., TypeScript compilation errors), the artifact was not stored. Check the
failuresarray for specific error messages. - If validation passed but the artifact is missing, check whether
storeObjectorupdateRefthrew an error. Look in Vercel function logs for "project_refs upsert failed" or "forge_objects insert failed".
Fix
- Validation failure: The most common cause is a TypeScript compilation error in the generated code. Run a manual sync -- generation is non-deterministic and a retry often produces valid output.
- Missing output language: Verify your
stateanchor.yamllists the language underoutputs.languages. Only languages in the spec are generated. - Database schema mismatch: If
project_refsorforge_objectshave missing columns, artifact storage fails silently. Check Supabase for pending migrations.
stateanchor.yaml parse errors
Symptom
The connect page shows "stateanchor.yaml has errors" or the sync run fails immediately at the parsing stage.
Diagnosis
Common YAML mistakes that cause parse failures:
- Indentation: YAML requires consistent indentation. Mixing tabs and spaces, or inconsistent indent levels, causes parse failures. Use 2-space indentation throughout.
- Unquoted special characters: Values containing colons, hashes, or brackets must be quoted. Example:
base_url: "https://api.example.com"(quoted because of the colon). - Anchor/alias rejection: StateAnchor rejects YAML anchors (
&anchor) and aliases (*alias) for security reasons. Inline all values explicitly. - Missing required fields: The spec requires
service,version, and at least one endpoint. Missing any of these causes a validation error.
Fix
# Correct stateanchor.yaml structure
service: my-api # required
version: "0.1.0" # required, must be quoted
server:
base_url: "https://api.example.com"
auth:
type: bearer
models:
User:
id: uuid
email: string
endpoints: # at least one required
- name: list_users
method: GET
path: /users
returns: User[]
outputs:
languages:
- typescript
docs: true
mcp: trueDashboard showing stale data
Symptom
The dashboard or project detail page shows old data after a successful sync. The last sync time, artifact count, or gate decision does not reflect the latest run.
Diagnosis
- Browser cache: The projects list API uses
cache: "no-store"but your browser may cache the page itself. Hard-refresh withCtrl+Shift+R(orCmd+Shift+R). - Sync run still running:Check the project detail page for a sync run in "running" status. The data updates only when the run completes.
- Dual status values: Some code paths write
status: "complete"while others writestatus: "completed". Both are valid success statuses.
Fix
- Hard-refresh the browser.
- Wait for any running sync to complete, then refresh.
- If data is still stale after 5 minutes, trigger a manual sync from the project detail page.
GitHub Action failing
Symptom
The stateanchor/sync-action GitHub Action fails in your CI workflow with an authentication error, token exchange failure, or 401 response.
Diagnosis
- OIDC token exchange:The sync action uses GitHub's OIDC provider to obtain a short-lived token. Your workflow must include
permissions: { id-token: write, contents: read }. - Action token scope:If the action reports "permission denied", verify the workflow has
contents: readpermission to read the repository. - api-base-url mismatch: The action must point to
https://stateanchor.dev. Verify theapi-base-urlinput in your workflow YAML.
Fix
# .github/workflows/stateanchor-sync.yml
name: StateAnchor Sync
on:
push:
branches: [main]
permissions:
id-token: write # ← required for OIDC token exchange
contents: read # ← required to read repo contents
jobs:
stateanchor-sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: stateanchor/sync-action@main
with:
mode: sync
config-path: stateanchor.yaml
api-base-url: https://stateanchor.devIf none of these solutions resolve your issue, contact support at support@stateanchor.dev with your project ID and the sync run ID showing the failure.