Zie619/n8n-workflows · warning · HTTPException

Rate limit exceeded. Please try again later.

Error message

Rate limit exceeded. Please try again later.

What it means

A 429 from GET /api/workflows/{filename} when check_rate_limit(client_ip) returns False. The server keeps a per-IP sliding/fixed window of allowed requests; exceeding it within the window raises HTTPException(429) with this message. It protects the file-detail endpoint from hammering.

Source

Thrown at api_server.py:320

    except Exception as e:
        raise HTTPException(
            status_code=500, detail=f"Error searching workflows: {str(e)}"
        )


@app.get("/api/workflows/{filename}")
async def get_workflow_detail(filename: str, request: Request):
    """Get detailed workflow information including raw JSON."""
    try:
        # Security: Validate filename to prevent path traversal
        if not validate_filename(filename):
            print(f"Security: Blocked path traversal attempt for filename: {filename}")
            raise HTTPException(status_code=400, detail="Invalid filename format")

        # Security: Rate limiting
        client_ip = request.client.host if request.client else "unknown"
        if not check_rate_limit(client_ip):
            raise HTTPException(
                status_code=429, detail="Rate limit exceeded. Please try again later."
            )

        # Get workflow metadata from database
        workflows, _ = db.search_workflows(f'filename:"{filename}"', limit=1)
        if not workflows:
            raise HTTPException(
                status_code=404, detail="Workflow not found in database"
            )

        workflow_meta = workflows[0]

        # Load raw JSON from file with security checks
        workflows_path = Path("workflows").resolve()

        # Find the file safely
        matching_file = None
        for subdir in workflows_path.iterdir():

View on GitHub (pinned to 94007c1445)

Solutions

  1. Wait for the rate-limit window to expire (typically seconds to a minute) before retrying.
  2. Cache detail responses client-side so revisiting a workflow does not re-hit the API.
  3. Reduce burstiness: debounce UI actions that trigger detail fetches.
  4. If you operate the server and the limit is genuinely too low, adjust the limit parameters in check_rate_limit()/its config rather than removing the check.

Example fix

// before
const data = await this.apiCall(`/workflows/${name}`);

// after (simple per-key client cache + backoff on 429)
if (!this._detailCache[name]) {
  for (let attempt = 0; attempt < 3; attempt++) {
    try { this._detailCache[name] = await this.apiCall(`/workflows/${name}`); break; }
    catch (e) { if (!e.message.includes('429')) throw e; await new Promise(r => setTimeout(r, 1000 * (attempt + 1))); }
  }
}
Defensive patterns

Strategy: retry

Try / catch

try {
  detail = await apiCall(`/workflows/${name}`);
} catch (e) {
  if (String(e.message).includes('429')) {
    await sleep(1500);            // let the window reset
    detail = await apiCall(`/workflows/${name}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Rapidly opening many workflow detail views from one IP (each click fires at least one request), automated scraping of /api/workflows/<name>, or a page-load sequence that fans out several detail requests concurrently.

Common situations: Browsing the gallery quickly in a demo; running load tests against the API; sharing an IP (office NAT/proxy) so many users collectively exhaust the limit.

Related errors


AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15). Data as JSON: /api/errors/0248b191ebe6bd66. Report an issue: GitHub.