Skip to main content
AI/MLjeremylongshore

webflow-common-errors

"Diagnose and fix Webflow Data API v2 errors \u2014 400, 401, 403, 404,\

Stars
2,267
Source
jeremylongshore/claude-code-plugins-plus-skills
Updated
2026-05-31
Slug
jeremylongshore--claude-code-plugins-plus-skills--webflow-common-errors
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/jeremylongshore/claude-code-plugins-plus-skills/HEAD/plugins/saas-packs/webflow-pack/skills/webflow-common-errors/SKILL.md -o .claude/skills/webflow-common-errors.md

Drops the SKILL.md into .claude/skills/webflow-common-errors.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Webflow Common Errors

Overview

Quick reference for the most common Webflow Data API v2 errors, their root causes, and concrete solutions. Covers every HTTP status code the API returns.

Prerequisites

  • webflow-api SDK installed
  • API token configured
  • Access to application logs

HTTP Error Reference

400 Bad Request — Invalid Input

{ "code": "validation_error", "message": "Invalid field data" }

Common causes:

  • Missing required field (name and slug are always required for CMS items)
  • Wrong field type (sending string for a Number field)
  • Invalid slug format (must be lowercase, hyphens only, no spaces)
  • Bulk request exceeds 100 items

Fix:

// Check collection schema before creating items
const collection = await webflow.collections.get(collectionId);
const requiredFields = collection.fields?.filter(f => f.isRequired);
console.log("Required fields:", requiredFields?.map(f => `${f.slug} (${f.type})`));

// Validate slug format
function isValidSlug(slug: string): boolean {
  return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug);
}

401 Unauthorized — Invalid Token

{ "code": "unauthorized", "message": "Not authorized" }

Common causes:

  • Token revoked or expired
  • Token copied with extra whitespace
  • Using v1 API key format with v2 endpoints

Fix:

# Verify token works
curl -s https://api.webflow.com/v2/sites \
  -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
  -w "\nHTTP Status: %{http_code}\n"

# Check for whitespace issues
echo -n "$WEBFLOW_API_TOKEN" | wc -c
// Programmatic token check
async function verifyToken(): Promise<boolean> {
  try {
    await webflow.sites.list();
    return true;
  } catch (err: any) {
    if (err.statusCode === 401) {
      console.error("Token invalid. Generate new token at developers.webflow.com");
      return false;
    }
    throw err;
  }
}

403 Forbidden — Missing Scope

{ "code": "forbidden", "message": "Insufficient permissions" }

Common causes:

  • Token missing required scope (e.g., calling CMS write with only cms:read)
  • Site token used for a different site
  • OAuth app not authorized for the scope

Fix:

// Required scopes by operation
const SCOPE_MAP: Record<string, string> = {
  "sites.list": "sites:read",
  "sites.publish": "sites:write",
  "collections.list": "cms:read",
  "collections.items.createItem": "cms:write",
  "pages.list": "pages:read",
  "forms.list": "forms:read",
  "products.list": "ecommerce:read",
  "products.create": "ecommerce:write",
  "orders.list": "ecommerce:read",
  "orders.refund": "ecommerce:write",
};

Generate a new token with the correct scopes at https://developers.webflow.com.


404 Not Found — Wrong Resource ID

{ "code": "not_found", "message": "Resource not found" }

Common causes:

  • Wrong site_id, collection_id, or item_id
  • Resource deleted
  • Using staging ID against live endpoint (or vice versa)

Fix:

// Discovery chain: always start from sites.list()
async function discoverResources() {
  const { sites } = await webflow.sites.list();
  console.log("Sites:", sites?.map(s => `${s.displayName}: ${s.id}`));

  for (const site of sites!) {
    const { collections } = await webflow.collections.list(site.id!);
    console.log(`  Collections in ${site.displayName}:`);
    for (const col of collections!) {
      console.log(`    ${col.displayName}: ${col.id}`);
    }
  }
}

409 Conflict — Duplicate Resource

{ "code": "conflict", "message": "Item with slug already exists" }

Common causes:

  • CMS item with same slug already exists in collection
  • Trying to create a resource that already exists

Fix:

// Check for existing slug before creating
async function createOrUpdate(collectionId: string, slug: string, fieldData: Record<string, any>) {
  const { items } = await webflow.collections.items.listItems(collectionId);
  const existing = items?.find(i => i.fieldData?.slug === slug);

  if (existing) {
    return webflow.collections.items.updateItem(collectionId, existing.id!, { fieldData });
  }
  return webflow.collections.items.createItem(collectionId, { fieldData: { slug, ...fieldData } });
}

429 Too Many Requests — Rate Limited

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Common causes:

  • Exceeded per-key rate limit
  • Site publish called more than once per minute
  • Rapid-fire requests without throttling

Fix:

// The SDK auto-retries 429s with exponential backoff.
// For manual control:
async function waitForRateLimit(retryAfterSeconds: number) {
  console.log(`Rate limited. Waiting ${retryAfterSeconds}s...`);
  await new Promise(r => setTimeout(r, retryAfterSeconds * 1000));
}

See webflow-rate-limits for comprehensive rate limit handling.


500/502/503 — Webflow Server Error

Fix:

# 1. Check Webflow status
curl -s https://status.webflow.com/api/v2/status.json | jq '.status'

# 2. Retry with backoff (SDK handles this automatically)
# 3. If persistent, check Webflow status page and open support ticket

Quick Diagnostic Commands

# Test API connectivity
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
  https://api.webflow.com/v2/sites

# Check rate limit headers
curl -v -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
  https://api.webflow.com/v2/sites 2>&1 | grep -i "x-ratelimit\|retry-after"

# List sites (quick token verification)
curl -s -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
  https://api.webflow.com/v2/sites | jq '.sites[].displayName'

# Check Webflow platform status
curl -s https://status.webflow.com/api/v2/status.json | jq '.status.description'

Error Handling Pattern

import { WebflowClient } from "webflow-api";

async function resilientCall<T>(
  operation: () => Promise<T>,
  label: string
): Promise<T> {
  try {
    return await operation();
  } catch (err: any) {
    const status = err.statusCode || err.status;

    const actionMap: Record<number, string> = {
      400: "Fix request payload — check field names and types",
      401: "Rotate token at developers.webflow.com",
      403: "Add missing scope to token",
      404: "Verify resource IDs with discovery chain",
      409: "Handle duplicate — update instead of create",
      429: "Wait for Retry-After header (SDK auto-retries)",
      500: "Webflow server error — retry later",
    };

    console.error(`[${label}] HTTP ${status}: ${actionMap[status] || "Unknown error"}`);
    console.error(`  Message: ${err.message}`);
    console.error(`  Body: ${JSON.stringify(err.body)}`);

    throw err;
  }
}

Escalation Path

  1. Check error code against this reference
  2. Run diagnostic commands above
  3. Collect evidence with webflow-debug-bundle
  4. Check Webflow Status
  5. Open support ticket with request ID and error details

Output

  • Identified error cause from HTTP status code
  • Applied targeted fix
  • Verified resolution

Resources

Next Steps

For comprehensive debugging, see webflow-debug-bundle.