owasp-amass/amass · warning

the context expired

Error message

the context expired

What it means

Crawl spiders a web page within a given scope, but first performs a non-blocking select on the provided context. If ctx is already done — cancelled or past its deadline — it returns 'the context expired' immediately instead of starting work. This is standard Go context propagation: the caller owns the crawl's lifetime.

Source

Thrown at internal/net/http/http.go:212

	req.Header.Set("Accept-Language", AcceptLang)
	for k, values := range r.Header {
		for _, v := range values {
			req.Header.Set(k, v)
		}
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	return RespToAmassResponse(resp), nil
}

// Crawl will spider the web page at the URL argument looking while staying within the scope provided.
func Crawl(ctx context.Context, u string, scope []string, max int, callback func(*Request, *Response)) error {
	select {
	case <-ctx.Done():
		return fmt.Errorf("the context expired")
	default:
	}

	var count int
	var m sync.Mutex
	filter := bf.NewDefaultStableBloomFilter(10000, 0.01)
	defer filter.Reset()
	attrs := []string{"action", "cite", "data", "formaction",
		"href", "longdesc", "poster", "src", "srcset", "xmlns"}
	tags := []string{"a", "area", "audio", "base", "blockquote", "button",
		"embed", "form", "frame", "frameset", "html", "iframe", "img", "input",
		"ins", "link", "noframes", "object", "q", "script", "source", "track", "video"}

	g := geziyor.NewGeziyor(&geziyor.Options{
		StartURLs:             []string{u},
		RobotsTxtDisabled:     true,
		UserAgent:             UserAgent,
		LogDisabled:           true,

View on GitHub (pinned to 79299dce87)

Solutions

  1. Increase the WithTimeout duration so it covers the expected crawl time.
  2. Do not pass an already-cancelled context; build a fresh one (context.Background() plus a new timeout).
  3. Audit upstream code for premature cancel() calls or parent contexts ending early.
  4. Treat the error as normal cancellation: stop work and propagate rather than retry blindly.

Example fix

// before
ctx, cancel := context.WithTimeout(parent, 500*time.Millisecond)
err := Crawl(ctx, url, scope, max, cb)  // deadline too short -> the context expired
// after
ctx, cancel := context.WithTimeout(parent, 30*time.Second)
err := Crawl(ctx, url, scope, max, cb)
Defensive patterns

Strategy: retry

Validate before calling

// Go — check before calling
select {
case <-ctx.Done():
	return fmt.Errorf("cannot start crawl: %v", ctx.Err())
default:
}

Try / catch

// Go
crawlCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := Crawl(crawlCtx, u, scope, max, cb); err != nil {
	if errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "the context expired") {
		// retry with a longer deadline or back off
	}
}

Prevention

When it happens

Trigger: Calling Crawl with a context that is already cancelled, a deadline that expired before the call, or a very short timeout (e.g. context.WithTimeout(ctx, 1*time.Millisecond)); also as in TestCrawl, where a test context expires during crawling.

Common situations: HTTP-handler parent contexts ending before slow crawls finish, test harnesses with tight deadlines, goroutine shutdown racing with crawl start.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of owasp-amass/amass@79299dce87 (2026-09-06). Data as JSON: /api/errors/a0d52eb308654788. Report an issue: GitHub.