projectdiscovery/nuclei · error
grpc: refusing to dial without executionId
Error message
grpc: refusing to dial without executionId
What it means
dialTarget refuses to connect when the executionId is empty. The grpc.Client captures executionID from the goja runtime at construction (nj.ExecutionId()); if nuclei never seeded the runtime or context with an execution id — i.e. the library is used outside a scan execution — every dial fails closed rather than bypassing network policy.
Source
Thrown at pkg/js/libs/grpc/invoke.go:51
}
// dialTarget builds a *grpc.ClientConn whose every connection is routed through
// nuclei's network policy. The host is validated up front and the actual dial
// is delegated to the execution's fastdialer via a custom context dialer, so
// IP/host denylists and RestrictLocalNetworkAccess are always enforced. The
// passthrough scheme guarantees the target is handed verbatim to our dialer
// (instead of gRPC's built in DNS resolver), keeping resolution and policy
// enforcement inside fastdialer.
func dialTarget(ctx context.Context, executionID, target string, cfg connConfig) (*grpc.ClientConn, error) {
host, _, err := net.SplitHostPort(target)
if err != nil {
return nil, fmt.Errorf("invalid grpc target %q (expected host:port): %w", target, err)
}
if host == "" {
return nil, fmt.Errorf("grpc target host cannot be empty")
}
if executionID == "" {
return nil, fmt.Errorf("grpc: refusing to dial without executionId")
}
if !protocolstate.IsHostAllowed(executionID, host) {
return nil, protocolstate.ErrHostDenied.Msgf(host)
}
dialers := protocolstate.GetDialersWithId(executionID)
if dialers == nil || dialers.Fastdialer == nil {
return nil, fmt.Errorf("grpc: dialers not initialized for executionId %q", executionID)
}
contextDialer := func(dialCtx context.Context, addr string) (net.Conn, error) {
return dialers.Fastdialer.Dial(dialCtx, "tcp", addr)
}
var creds credentials.TransportCredentials
if cfg.plaintext {
creds = insecure.NewCredentials()
} else {
serverName := cfg.serverNameView on GitHub (pinned to 265b3a3dec)
Solutions
- Run the gRPC code inside a nuclei code-protocol template so the engine attaches the executionId
- From Go/tests, seed the runtime/context with the execution id the same way nuclei does before constructing the Client
- Register protocolstate dialers for that same executionId, otherwise the next failure is 'dialers not initialized'
Example fix
// before: standalone test runtime, no execution bound to it
const client = new grpc.Client('grpc.acme.com:443');
client.Invoke('acme.v1.Svc/Get', '{}'); // -> refusing to dial without executionId
// after: same code runs as a nuclei code template (code protocol),
// which seeds the executionId on the goja runtime automatically
// template: code:
// const grpc = require('nuclei/grpc');
// const c = new grpc.Client('grpc.acme.com:443');
// c.Invoke('acme.v1.Svc/Get', '{}'); Defensive patterns
Strategy: try-catch
Try / catch
let client;
try {
client = new grpc.Client(target, opts);
client.Connect();
} catch (e) {
if (/without executionId/.test(e.message || '')) {
// running outside a nuclei execution: move this code into a code-protocol template
}
} Prevention
- Run gRPC code only inside nuclei code templates, where the engine seeds the executionId
- From SDK/tests, replicate nuclei' runtime setup (execution id + protocolstate) before constructing clients
- Do not instantiate the JS grpc library in fresh goja runtimes without the scan scaffolding
When it happens
Trigger: Driving pkg/js/libs/grpc from standalone Go code or unit tests where the goja runtime/context carries no execution id; constructing a Client before the execution context was attached to the runtime; reusing a Client object across runtimes.
Common situations: SDK/embedded usage (lib/) that instantiates the JS libraries outside a real scan; developers testing Client.Invoke directly without nuclei's runtime initialization.
Related errors
- grpc: dialers not initialized for executionId %q
- http: executionId not set
- goimpacket: no fastdialer registered for executionId %q
- invalid grpc target %q (expected host:port): %w
- grpc target host cannot be empty
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/6de3b3b23cdd236b.
Report an issue: GitHub.