projectdiscovery/nuclei · error

invalid request type %s

Error message

invalid request type %s

What it means

NewFlowExecutor (pkg/tmplexec/flow/flow_executor.go) buckets each protocols.Request by Type() so JS functions (http(), dns(), tcp(), ...) can dispatch to them. The switch handles DNS, HTTP, Network, File, Headless, SSL, Websocket, WHOIS, Code, Javascript and OfflineHTTP; anything else hits the default and returns 'invalid request type %s' with the request's Type().String(). This is the root error that surfaces wrapped as errors 462/463.

Source

Thrown at pkg/tmplexec/flow/flow_executor.go:91

		case templateTypes.FileProtocol:
			allprotos[templateTypes.FileProtocol.String()] = append(allprotos[templateTypes.FileProtocol.String()], req)
		case templateTypes.HeadlessProtocol:
			allprotos[templateTypes.HeadlessProtocol.String()] = append(allprotos[templateTypes.HeadlessProtocol.String()], req)
		case templateTypes.SSLProtocol:
			allprotos[templateTypes.SSLProtocol.String()] = append(allprotos[templateTypes.SSLProtocol.String()], req)
		case templateTypes.WebsocketProtocol:
			allprotos[templateTypes.WebsocketProtocol.String()] = append(allprotos[templateTypes.WebsocketProtocol.String()], req)
		case templateTypes.WHOISProtocol:
			allprotos[templateTypes.WHOISProtocol.String()] = append(allprotos[templateTypes.WHOISProtocol.String()], req)
		case templateTypes.CodeProtocol:
			allprotos[templateTypes.CodeProtocol.String()] = append(allprotos[templateTypes.CodeProtocol.String()], req)
		case templateTypes.JavascriptProtocol:
			allprotos[templateTypes.JavascriptProtocol.String()] = append(allprotos[templateTypes.JavascriptProtocol.String()], req)
		case templateTypes.OfflineHTTPProtocol:
			// offlinehttp is run in passive mode but templates are same so instead of using offlinehttp() we use http() in flow
			allprotos[templateTypes.HTTPProtocol.String()] = append(allprotos[templateTypes.OfflineHTTPProtocol.String()], req)
		default:
			return nil, fmt.Errorf("invalid request type %s", req.Type().String())
		}
	}
	f := &FlowExecutor{
		allProtocols: allprotos,
		options:      options,
		allErrs: mapsutil.SyncLockMap[string, error]{
			ReadOnly: atomic.Bool{},
			Map:      make(map[string]error),
		},
		protoFunctions: map[string]func(call goja.FunctionCall, runtime *goja.Runtime) goja.Value{},
		results:        results,
		ctx:            ctx,
		program:        program,
		executed:       mapsutil.NewSyncLockMap[string, struct{}](),
	}
	return f, nil
}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Update nuclei — the flow switch is extended as protocols gain flow support
  2. Split the template: keep only supported protocol sections in a flow template, move the rest to separate normal templates
  3. If building requests programmatically, ensure each Request.Type() returns one of the mapped protocol types before enabling options.Flow
  4. Validate with `nuclei -validate -t template.yaml`; a template that passes validation but still hits this on old binaries means version skew — upgrade

Example fix

# before: unsupported section inside a flow template
flow: |
  http()
requests: []
# some-toolkit-section:
#   custom: true

# after: only supported protocol sections (http/dns/tcp/file/headless/ssl/websocket/whois/code/javascript) remain
Defensive patterns

Strategy: validation

Validate before calling

// Gate NewFlowExecutor inputs to exactly the supported switch set (flow_executor.go):
var flowSupported = map[templateTypes.ProtocolType]bool{
    templateTypes.DNSProtocol: true, templateTypes.FileProtocol: true,
    templateTypes.HTTPProtocol: true, templateTypes.OfflineHTTPProtocol: true,
    templateTypes.HeadlessProtocol: true, templateTypes.NetworkProtocol: true,
    templateTypes.SSLProtocol: true, templateTypes.WebsocketProtocol: true,
    templateTypes.WHOISProtocol: true, templateTypes.CodeProtocol: true,
    templateTypes.JavascriptProtocol: true,
}
for _, r := range requests {
    if !flowSupported[r.Type()] {
        return fmt.Errorf("request type %s cannot be used inside a flow template", r.Type().String())
    }
}

Type guard

func isFlowSupportedType(t templateTypes.ProtocolType) bool { return flowSupported[t] }

Try / catch

f, err := flow.NewFlowExecutor(requests, ctx, options, results, program)
if err != nil {
    return fmt.Errorf("template %s: %w (supported: dns,file,http,offline-http,headless,tcp,ssl,websocket,whois,code,javascript)", options.TemplateID, err)
}

Prevention

When it happens

Trigger: Any request in the list whose Type() returns WorkflowProtocol ('workflow'), InvalidProtocol ('invalid'), or zero-value/out-of-range enum. Realistically: a workflow document mistaken for a flow template, a malformed protocol section parsed into an invalid type, or an SDK-provided custom Request with an unmapped Type().

Common situations: Mixing workflow and flow syntax in one template; older nuclei binaries meeting newer protocol types (the switch grows over time — ssl/websocket/headless were added incrementally); programmatic template construction where the request's type tag is never set.

Related errors


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