projectdiscovery/nuclei · error

cookie reuse enabled but cookie-jar is nil

Error message

cookie reuse enabled but cookie-jar is nil

What it means

Headless requests reuse session cookies across steps/templates unless the request sets DisableCookie: true, and that reuse requires a jar attached to the input context (input.CookieJar). If cookie reuse is enabled but the jar is nil, nuclei fails fast rather than silently running without session state. The CLI always builds inputs via contextargs constructors that create a jar, so this is essentially an SDK/embedding error.

Source

Thrown at pkg/protocols/headless/request.go:159

	defer func() {
		_ = instance.Close()
	}()

	instance.SetInteractsh(request.options.Interactsh)

	if _, err := url.Parse(input.MetaInput.Input); err != nil {
		request.options.Output.Request(request.options.TemplatePath, input.MetaInput.Input, request.Type().String(), err)
		request.options.Progress.IncrementFailedRequestsBy(1)
		return errors.Wrap(err, errCouldNotGetHtmlElement)
	}
	options := &engine.Options{
		Timeout:       time.Duration(request.options.Options.PageTimeout) * time.Second,
		DisableCookie: request.DisableCookie,
		Options:       request.options.Options,
	}

	if !options.DisableCookie && input.CookieJar == nil {
		return errors.New("cookie reuse enabled but cookie-jar is nil")
	}

	timeStart := time.Now()
	out, page, err := instance.Run(input, request.Steps, payloads, options)
	runDuration := time.Since(timeStart)
	if err != nil {
		request.options.Output.Request(request.options.TemplatePath, input.MetaInput.Input, request.Type().String(), err)
		request.options.Progress.IncrementFailedRequestsBy(1)
		return errors.Wrap(err, errCouldNotGetHtmlElement)
	}
	defer page.Close()

	page.InteractshURLs = append(interactshURLs, page.InteractshURLs...)

	reqLog := instance.GetRequestLog()
	navigatedURL := request.getLastNavigationURLWithLog(reqLog) // also known as matchedURL if there is a match

	request.options.Output.Request(request.options.TemplatePath, input.MetaInput.Input, request.Type().String(), nil)

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Build inputs with contextargs.NewWithInput(ctx, targetURL) / NewWithMetaInput — they initialize the cookie jar
  2. Or attach a jar manually: jar, _ := cookiejar.New(nil); ctx.CookieJar = jar
  3. If the template does not need sessions, set `disable_cookie: true` on the headless request

Example fix

// before
ctx := &contextargs.Context{MetaInput: &contextargs.MetaInput{Input: url}}

// after
ctx := contextargs.NewWithInput(context.Background(), url)
Defensive patterns

Strategy: validation

Validate before calling

ctx := contextargs.NewWithInput(context.Background(), targetURL) // constructor initializes CookieJar
if !request.DisableCookie && ctx.CookieJar == nil {
    jar, _ := cookiejar.New(nil)
    ctx.CookieJar = jar
}

Prevention

When it happens

Trigger: Embedding nuclei (lib/ or SDK) and constructing contextargs.Context with a struct literal or a constructor that skips CookieJar, then executing a headless template with default (enabled) cookie reuse. The CLI's NewWithInput/NewWithMetaInput always allocate a jar, so CLI users normally never see it.

Common situations: SDK users copying older example code that built Context{...} directly; tests creating bare inputs; custom input providers that bypass the provided constructors.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/e80dfbab5ff8b117. Report an issue: GitHub.