fix(loader): replace panic with error handling in template loader

Replace panic with proper error return when dialers are missing,
allowing callers to handle the situation gracefully.

Changes:
- Modify LoadTemplatesWithTags to return ([]*templates.Template, error)
- Modify LoadTemplates to return ([]*templates.Template, error)
- Modify Load to return error
- Replace panic("dialers with executionId...") with fmt.Errorf
- Replace panic("could not create wait group") with fmt.Errorf
- Update all callers to handle the new error return

Callers updated:
- internal/runner/lazy.go
- internal/runner/runner.go
- internal/server/nuclei_sdk.go
- lib/multi.go
- lib/sdk.go
- cmd/integration-test/library.go
- pkg/protocols/common/automaticscan/util.go
- pkg/catalog/loader/loader_bench_test.go

Fixes #6674
This commit is contained in:
bimakw
2026-02-04 20:31:22 +07:00
parent 8aa427a6ea
commit 75525ed431
9 changed files with 46 additions and 24 deletions
+3 -1
View File
@@ -132,7 +132,9 @@ func executeNucleiAsLibrary(templatePath, templateURL string) ([]string, error)
if err != nil {
return nil, errors.Wrap(err, "could not create loader")
}
store.Load()
if err := store.Load(); err != nil {
return nil, errors.Wrap(err, "could not load templates")
}
_ = engine.Execute(context.Background(), store.Templates(), provider.NewSimpleInputProviderWithUrls(defaultOpts.ExecutionId, templateURL))
engine.WorkPool().Wait() // Wait for the scan to finish
+7 -4
View File
@@ -67,7 +67,10 @@ func GetAuthTmplStore(opts *types.Options, catalog catalog.Catalog, execOpts *pr
// GetLazyAuthFetchCallback returns a lazy fetch callback for auth secrets
func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret {
return func(d *authx.Dynamic) error {
tmpls := opts.TemplateStore.LoadTemplates([]string{d.TemplatePath})
tmpls, err := opts.TemplateStore.LoadTemplates([]string{d.TemplatePath})
if err != nil {
return fmt.Errorf("failed to load templates: %w", err)
}
if len(tmpls) == 0 {
return fmt.Errorf("%w for path: %s", disk.ErrNoTemplatesFound, d.TemplatePath)
}
@@ -140,9 +143,9 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
// log result of template in result file/screen
_ = writer.WriteResult(e, opts.ExecOpts.Output, opts.ExecOpts.Progress, opts.ExecOpts.IssuesClient)
}
_, err := tmpl.Executer.ExecuteWithResults(ctx)
if err != nil {
finalErr = err
_, execErr := tmpl.Executer.ExecuteWithResults(ctx)
if execErr != nil {
finalErr = execErr
}
// store extracted result in auth context
d.Extracted = data
+3 -1
View File
@@ -660,7 +660,9 @@ func (r *Runner) RunEnumeration() error {
}
return nil // exit
}
store.Load()
if err := store.Load(); err != nil {
return err
}
// TODO: remove below functions after v3 or update warning messages
templates.PrintDeprecatedProtocolNameMsgIfApplicable(r.options.Silent, r.options.Verbose)
+3 -1
View File
@@ -125,7 +125,9 @@ func newNucleiExecutor(opts *NucleiExecutorOptions) (*nucleiExecutor, error) {
if err != nil {
return nil, errors.Wrap(err, "Could not create loader options.")
}
store.Load()
if err := store.Load(); err != nil {
return nil, errors.Wrap(err, "Could not load templates.")
}
return &nucleiExecutor{
engine: executorEngine,
+3 -1
View File
@@ -150,7 +150,9 @@ func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOptsCtx(ctx context.Context, t
if err != nil {
return errkit.Wrapf(err, "Could not create loader client: %s", err)
}
store.Load()
if err := store.Load(); err != nil {
return errkit.Wrapf(err, "Could not load templates: %s", err)
}
inputProvider := provider.NewSimpleInputProviderWithUrls(e.eng.opts.ExecutionId, targets...)
+3 -1
View File
@@ -110,7 +110,9 @@ func (e *NucleiEngine) LoadAllTemplates() error {
if err != nil {
return errkit.Wrapf(err, "Could not create loader client: %s", err)
}
e.store.Load()
if err := e.store.Load(); err != nil {
return errkit.Wrapf(err, "Could not load templates: %s", err)
}
e.templatesLoaded = true
return nil
}
+13 -7
View File
@@ -333,9 +333,14 @@ func (store *Store) RegisterPreprocessor(preprocessor templates.Preprocessor) {
// Load loads all the templates from a store, performs filtering and returns
// the complete compiled templates for a nuclei execution configuration.
func (store *Store) Load() {
store.templates = store.LoadTemplates(store.finalTemplates)
func (store *Store) Load() error {
templates, err := store.LoadTemplates(store.finalTemplates)
if err != nil {
return err
}
store.templates = templates
store.workflows = store.LoadWorkflows(store.finalWorkflows)
return nil
}
var templateIDPathMap map[string]string
@@ -637,7 +642,7 @@ func isParsingError(store *Store, message string, template string, err error) bo
}
// LoadTemplates takes a list of templates and returns paths for them
func (store *Store) LoadTemplates(templatesList []string) []*templates.Template {
func (store *Store) LoadTemplates(templatesList []string) ([]*templates.Template, error) {
return store.LoadTemplatesWithTags(templatesList, nil)
}
@@ -668,7 +673,8 @@ func (store *Store) LoadWorkflows(workflowsList []string) []*templates.Template
// LoadTemplatesWithTags takes a list of templates and extra tags
// returning templates that match.
func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templates.Template {
// Returns an error if dialers are not initialized for the given execution ID.
func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) ([]*templates.Template, error) {
defer store.saveMetadataIndexOnce()
indexFilter := store.indexFilter
@@ -708,7 +714,7 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
wgLoadTemplates, errWg := syncutil.New(syncutil.WithSize(concurrency))
if errWg != nil {
panic("could not create wait group")
return nil, fmt.Errorf("could not create wait group: %w", errWg)
}
if typesOpts.ExecutionId == "" {
@@ -717,7 +723,7 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
dialers := protocolstate.GetDialersWithId(typesOpts.ExecutionId)
if dialers == nil {
panic("dialers with executionId " + typesOpts.ExecutionId + " not found")
return nil, fmt.Errorf("dialers with executionId %s not found", typesOpts.ExecutionId)
}
for _, templatePath := range includedTemplates {
@@ -852,7 +858,7 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
return loadedTemplates.Slice[i].Path < loadedTemplates.Slice[j].Path
})
return loadedTemplates.Slice
return loadedTemplates.Slice, nil
}
// IsHTTPBasedProtocolUsed returns true if http/headless protocol is being used for
+7 -7
View File
@@ -71,7 +71,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -89,7 +89,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -107,7 +107,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -125,7 +125,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -143,7 +143,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -161,7 +161,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
@@ -181,7 +181,7 @@ func BenchmarkLoadTemplates(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
}
})
}
+4 -1
View File
@@ -37,7 +37,10 @@ func getTemplateDirs(opts Options) ([]string, error) {
// LoadTemplatesWithTags loads and returns templates with given tags
func LoadTemplatesWithTags(opts Options, templateDirs []string, tags []string, logInfo bool) ([]*templates.Template, error) {
finalTemplates := opts.Store.LoadTemplatesWithTags(templateDirs, tags)
finalTemplates, err := opts.Store.LoadTemplatesWithTags(templateDirs, tags)
if err != nil {
return nil, errors.Wrap(err, "could not load templates")
}
if len(finalTemplates) == 0 {
return nil, errors.New("could not find any templates with tech tag")
}