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
- Nothing to fix if the target genuinely has no more actions — crawl finished
- Check the target in a real browser; anti-bot walls can hide all actionable elements
- 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
- Validate the target renders interactive content (test in a real browser)
- Check for anti-bot walls blocking headless rendering
- Log queue size periodically to know when actions are exhausted
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.