{"record":{"id":"2abd7ad55a8a671e","repo":"projectdiscovery/nuclei","slug":"goimpacket-no-fastdialer-registered-for-execution","errorCode":null,"errorMessage":"goimpacket: no fastdialer registered for executionId %q","messagePattern":"goimpacket: no fastdialer registered for executionId %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/gptransport/dialer.go","lineNumber":55,"sourceCode":"\treturn &gptr.Dialer{\n\t\tDialFn: func(ctx context.Context, network, address string) (net.Conn, error) {\n\t\t\treturn DialWithExec(ctx, execID, network, address)\n\t\t},\n\t}\n}\n\n// DialWithExec performs the fastdialer dial after enforcing host policy.\nfunc DialWithExec(ctx context.Context, execID, network, address string) (net.Conn, error) {\n\thost, _, err := net.SplitHostPort(address)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid address %q: %w\", address, err)\n\t}\n\tif !protocolstate.IsHostAllowed(execID, host) {\n\t\treturn nil, protocolstate.ErrHostDenied.Msgf(host)\n\t}\n\tdialer := protocolstate.GetDialersWithId(execID)\n\tif dialer == nil || dialer.Fastdialer == nil {\n\t\treturn nil, fmt.Errorf(\"goimpacket: no fastdialer registered for executionId %q\", execID)\n\t}\n\treturn dialer.Fastdialer.Dial(ctx, network, address)\n}\n\n// ExecutionIDFromCtx pulls the executionId set by nuclei on its goja runtime\n// or scan context. Returns \"\" when the context carries no id.\nfunc ExecutionIDFromCtx(ctx context.Context) string {\n\tif ctx == nil {\n\t\treturn \"\"\n\t}\n\tif v := ctx.Value(\"executionId\"); v != nil {\n\t\tif id, ok := v.(string); ok {\n\t\t\treturn id\n\t\t}\n\t}\n\treturn \"\"\n}\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/gptransport/dialer.go#L37-L73","documentation":"The context carried an executionId, but protocolstate.GetDialersWithId(execID) returned nil (or a record without Fastdialer), meaning no dialer set was registered for that execution. The exec-bound dial path refuses to fall back to a default dialer, so it fails closed instead of bypassing fastdialer and host policy.","triggerScenarios":"protocolstate was never initialized for the execution; the execution already finished and its dialers were released while a goroutine still dials; the executionId in the context does not match the id used at registration time.","commonSituations":"Long-lived background goroutines surviving past scan teardown; SDK users inventing their own execution ids without registering dialers; races between execution cleanup and in-flight SMB/DCOM operations.","solutions":["Initialize/verify protocolstate dialers for the executionId before starting any work that dials","Cancel or complete in-flight goimpacket work before the execution's dialers are released","Log the execID at both registration and dial time and confirm they match exactly"],"exampleFix":"// before: dials before dialers exist (or after they were released)\nconn, err := gptransport.DialWithExec(ctx, execID, \"tcp\", addr)\n\n// after: fail fast with a lifecycle hint instead of an opaque dial error\nif d := protocolstate.GetDialersWithId(execID); d == nil || d.Fastdialer == nil {\n\treturn fmt.Errorf(\"dialers not registered for execution %s; initialize protocolstate first\", execID)\n}\nconn, err := gptransport.DialWithExec(ctx, execID, \"tcp\", addr)","handlingStrategy":"validation","validationCode":"if d := protocolstate.GetDialersWithId(execID); d == nil || d.Fastdialer == nil {\n    return fmt.Errorf(\"no dialers registered for execution %s; initialize protocolstate first\", execID)\n}\nconn, err := gptransport.DialWithExec(ctx, execID, \"tcp\", addr)","typeGuard":"func hasRegisteredDialers(execID string) bool {\n    d := protocolstate.GetDialersWithId(execID)\n    return d != nil && d.Fastdialer != nil\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no fastdialer registered\") {\n    // lifecycle bug: dialers uninitialized or released; re-init or abort, do not silently retry","preventionTips":["Initialize protocolstate dialers per execution before any dialing goroutine starts","Complete or cancel SMB/DCOM work before the execution is torn down","Log the executionId at registration and at dial time to catch mismatches early"],"tags":["network","go","lifecycle","dialer"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}