projectdiscovery/katana · info

ErrNoCrawlingAction

ErrNoCrawlingAction

Error message

no more actions to crawl

What it means

ErrNoCrawlingAction signals that the headless crawler's crawl queue is empty and there are no navigations left, so no further actions can be executed. Crawl treats it specially: inside crawlFn it means 'stop gracefully' (returns nil) rather than a failure. It is the headless engine's way of terminating the crawl loop.

Source

Thrown at pkg/engine/headless/crawler/crawler.go:327

					c.logger.Debug("Skipping action as it is taking too long", slog.String("action", action.String()))
					consecutiveFailures++
					continue
				}

				c.logger.Debug("Skipping action due to site-specific error",
					slog.String("error", err.Error()),
					slog.String("action", action.String()),
				)
				consecutiveFailures++
				continue
			}

			consecutiveFailures = 0
		}
	}
}

var ErrNoCrawlingAction = errors.New("no more actions to crawl")

func (c *Crawler) crawlFn(ctx context.Context, action *types.Action, page *browser.BrowserPage) error {
	defer func() {
		c.launcher.PutBrowserToPool(page)
	}()

	currentPageHash, _, err := getPageHash(page)
	if err != nil {
		return err
	}

	c.logger.Debug("Processing action - current state",
		slog.String("current_page_hash", currentPageHash),
		slog.String("action_origin_id", action.OriginID),
		slog.String("action", action.String()),
	)

	if action.OriginID != "" && action.OriginID != currentPageHash {

View on GitHub (pinned to e3e742739c)

Solutions

  1. Nothing to fix if the target genuinely has no more actions — crawl finished
  2. Check the target in a real browser; anti-bot walls can hide all actionable elements
  3. Ensure --headless options/proxy aren't blocking page rendering, and review hooks that may consume or skip actions

Example fix

// before: failing on any Crawl error
if err := c.Crawl(ctx); err != nil { return err }
// after
if err := c.Crawl(ctx); err != nil && !errors.Is(err, crawler.ErrNoCrawlingAction) { return err }
Defensive patterns

Strategy: fallback

Validate before calling

// nothing to validate pre-call; ensure the target page has actionable elements
// e.g. verify selectors exist before crawling:
if len(actions) == 0 && queue.Size() == 0 { skip crawl }

Type guard

func isNoCrawlAction(err error) bool { return errors.Is(err, crawler.ErrNoCrawlingAction) }

Try / catch

if err := c.Crawl(ctx); err != nil {
    if errors.Is(err, crawler.ErrNoCrawlingAction) {
        return nil // graceful end of crawl
    }
    return err
}

Prevention

When it happens

Trigger: Returned from the queue-pop path (crawler.go:419) when c.crawlQueue.Size() == 0 and no navigation actions remain; also returned by Crawl when len(navigations) == 0 and the crawl queue is empty at start.

Common situations: Crawl of a page with no interactive elements or links; all crawlable actions already executed or exhausted due to consecutive failures; page blocked by login/JS challenge so nothing is discoverable.

Related errors


AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03). Data as JSON: /api/errors/acaf52c1a898e92a. Report an issue: GitHub.