Skip to content

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

Open
hanzhcn wants to merge 1 commit intoprojectdiscovery:devfrom
hanzhcn:dev
Open

fix: replace panic with error handling in template loader (#6674)#7107
hanzhcn wants to merge 1 commit intoprojectdiscovery:devfrom
hanzhcn:dev

Conversation

@hanzhcn
Copy link

@hanzhcn hanzhcn commented Mar 4, 2026

Summary

This PR fixes Issue #6674 by replacing panic statements with proper error handling in the template loader when dialers are missing for a given execution ID.

Changes

Core Fix (pkg/catalog/loader/loader.go)

  • Replaced panic("dialers with executionId ... not found") with return nil, fmt.Errorf("dialers with executionId %s not found", ...)
  • Updated LoadTemplatesWithTags() and LoadTemplates() function signatures to return error
  • Also fixed wait group creation panic to return proper error

Callers Updated

  • internal/runner/lazy.go: Lazy auth template loading now properly handles the error and wraps it with context
  • pkg/protocols/common/automaticscan/util.go: Automatic tech detection template loading propagates errors correctly
  • pkg/catalog/loader/loader_bench_test.go: Updated benchmark tests to handle new error return values

Testing

  • All existing tests pass
  • Build verification successful (go build ./...)
  • Test verification successful (go test ./pkg/catalog/loader/... ./internal/runner/... ./pkg/protocols/common/automaticscan/...)

Impact

This change enables graceful error handling instead of hard panics, allowing callers to handle the error condition appropriately. The Load() method uses logger.Fatal() for backward compatibility while providing a clear error message.


Closes #6674
/claim #6674

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved error handling and propagation for template loading operations, ensuring failures are properly captured and reported rather than silently ignored.
    • Enhanced error messages to provide clearer context when template-related issues occur.
    • Increased reliability by enforcing template validation constraints.

…covery#6674)

- Replace panic with proper error return in LoadTemplatesWithTags
- Update LoadTemplates and LoadTemplatesWithTags signatures to return error
- Update callers in lazy.go and automaticscan/util.go to handle errors
- Update benchmark tests to handle new error return values

Closes projectdiscovery#6674
@neo-by-projectdiscovery-dev
Copy link

neo-by-projectdiscovery-dev bot commented Mar 4, 2026

Review already completed and posted to GitHub for PR #7107 at commit a14126a.

Review Status: ✅ Posted
Result: No exploitable security vulnerabilities found
Files Analyzed: 4 files

  • pkg/catalog/loader/loader.go
  • internal/runner/lazy.go
  • pkg/protocols/common/automaticscan/util.go
  • pkg/catalog/loader/loader_bench_test.go

Summary: The PR replaces panic statements with proper error handling in the template loader, which is a positive code quality improvement with no security impact. The error messages expose only internal runtime identifiers (executionId), not sensitive data.

GitHub Comment ID: 3995805145

View the PR: #7107

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2026

Walkthrough

Replaces panic-based error handling with proper error returns in the template loader. LoadTemplates and LoadTemplatesWithTags now return error values to propagate loading failures, including missing dialers and missing templates. Callers updated to capture and handle these errors.

Changes

Cohort / File(s) Summary
Core Loader Updates
pkg/catalog/loader/loader.go
Changed LoadTemplates and LoadTemplatesWithTags signatures to return ([]*templates.Template, error). Now propagates errors from wait-group creation and dialer initialization instead of panicking. Callers explicitly handle returned errors.
Benchmark Test Updates
pkg/catalog/loader/loader_bench_test.go
Updated all LoadTemplates call sites to handle the new two-value return signature by assigning both values instead of one.
Caller Error Handling
internal/runner/lazy.go, pkg/protocols/common/automaticscan/util.go
Added error capture and handling for LoadTemplates and LoadTemplatesWithTags calls. Errors are now checked and returned or logged rather than ignored.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 No more panics in the night,
Proper errors set things right!
Where templates fail to load with grace,
Now errors find their rightful place! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: replacing panic with error handling in the template loader, which is the core objective of the changeset.
Linked Issues check ✅ Passed All objectives from issue #6674 are met: panic replaced with error return, function signatures updated to propagate errors, callers updated to handle errors, and error conditions documented.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue #6674; there are no out-of-scope modifications beyond the error handling refactoring.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
internal/runner/lazy.go (1)

70-73: Include the template path in the wrapped load error.

At Line 72, the wrap message loses which template path failed, which makes multi-secret debugging harder.

Suggested tweak
-		if err != nil {
-			return errkit.Wrap(err, "failed to load template")
-		}
+		if err != nil {
+			return errkit.Wrapf(err, "failed to load template for path: %s", d.TemplatePath)
+		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/runner/lazy.go` around lines 70 - 73, The error wrap when loading
templates via opts.TemplateStore.LoadTemplates([]string{d.TemplatePath}) omits
which template path failed; update the errkit.Wrap call to include
d.TemplatePath in the message (e.g., "failed to load template %s") so the
wrapped error shows the problematic template path when LoadTemplates returns an
error.
pkg/catalog/loader/loader.go (1)

336-343: Add a non-fatal error variant for Load() to enable proper error handling in SDK/server code paths.

The Load() method at lines 336-343 terminates with store.logger.Fatal() when template loading fails, preventing callers in lib/sdk.go:102, internal/server/nuclei_sdk.go, and lib/multi.go from returning structured errors. These call sites are functions that declare error returns, but Load()'s fatal behavior prevents error propagation.

Consider adding a LoadE() error variant (following the codebase pattern used in LoadTemplatesOnlyMetadata() at line 392) and keeping Load() for CLI-oriented callers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/catalog/loader/loader.go` around lines 336 - 343, The current Store.Load
method calls store.logger.Fatal on template load errors which prevents callers
from handling errors; add a new method Store.LoadE() error that performs the
same work but returns an error instead of exiting (call
LoadTemplates(store.finalTemplates), if err return fmt.Errorf(...), otherwise
set store.templates and store.workflows and return nil), keep the existing
Store.Load as a thin CLI helper that calls Store.LoadE() and converts any
returned error into store.logger.Fatal to preserve existing CLI behavior;
reference Store.Load, Store.LoadE, LoadTemplates, LoadTemplatesOnlyMetadata, and
store.logger.Fatal to locate and implement the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/catalog/loader/loader_bench_test.go`:
- Line 74: Benchmarks are currently discarding errors from store.LoadTemplates,
which can hide failures; replace the blank assignment with error handling inside
each benchmark loop by capturing the returned error from store.LoadTemplates
(called on the store variable) and failing the benchmark on error (e.g., if err
!= nil { b.Fatalf("LoadTemplates failed: %v", err) }) or move the call outside
the per-iteration loop if it shouldn’t run every iteration; apply this change
for every occurrence of store.LoadTemplates in loader_bench_test.go so errors
aren’t silently ignored.

In `@pkg/catalog/loader/loader.go`:
- Around line 643-646: Update the method comments for Store.LoadTemplates and
the related LoadTemplatesWithTags to document the new error contract: list
concrete failure modes callers must handle (e.g., missing dialers / connection
setup failure, wait-group or goroutine setup errors, template not found or path
resolution failures, I/O/read/parsing errors, and permission/OS errors), and
state that the function may return a non-nil error on these conditions instead
of returning only successful results; reference the function names
Store.LoadTemplates and Store.LoadTemplatesWithTags in the comments so callers
can find the documented error cases.

---

Nitpick comments:
In `@internal/runner/lazy.go`:
- Around line 70-73: The error wrap when loading templates via
opts.TemplateStore.LoadTemplates([]string{d.TemplatePath}) omits which template
path failed; update the errkit.Wrap call to include d.TemplatePath in the
message (e.g., "failed to load template %s") so the wrapped error shows the
problematic template path when LoadTemplates returns an error.

In `@pkg/catalog/loader/loader.go`:
- Around line 336-343: The current Store.Load method calls store.logger.Fatal on
template load errors which prevents callers from handling errors; add a new
method Store.LoadE() error that performs the same work but returns an error
instead of exiting (call LoadTemplates(store.finalTemplates), if err return
fmt.Errorf(...), otherwise set store.templates and store.workflows and return
nil), keep the existing Store.Load as a thin CLI helper that calls Store.LoadE()
and converts any returned error into store.logger.Fatal to preserve existing CLI
behavior; reference Store.Load, Store.LoadE, LoadTemplates,
LoadTemplatesOnlyMetadata, and store.logger.Fatal to locate and implement the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b3bafbe4-6a8f-40de-a8fa-d8d5826513e3

📥 Commits

Reviewing files that changed from the base of the PR and between b2ab7d3 and a14126a.

📒 Files selected for processing (4)
  • internal/runner/lazy.go
  • pkg/catalog/loader/loader.go
  • pkg/catalog/loader/loader_bench_test.go
  • pkg/protocols/common/automaticscan/util.go


for b.Loop() {
_ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don’t drop LoadTemplates errors inside benchmark loops.

At Lines 74/92/110/128/146/164/184, silently discarding errors can benchmark an error path and mask loader regressions.

Suggested pattern (apply to each benchmark loop)
-		for b.Loop() {
-			_, _ = store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory})
-		}
+		for b.Loop() {
+			if _, err := store.LoadTemplates([]string{config.DefaultConfig.TemplatesDirectory}); err != nil {
+				b.Fatalf("could not load templates: %s", err)
+			}
+		}

Also applies to: 92-92, 110-110, 128-128, 146-146, 164-164, 184-184

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/catalog/loader/loader_bench_test.go` at line 74, Benchmarks are currently
discarding errors from store.LoadTemplates, which can hide failures; replace the
blank assignment with error handling inside each benchmark loop by capturing the
returned error from store.LoadTemplates (called on the store variable) and
failing the benchmark on error (e.g., if err != nil { b.Fatalf("LoadTemplates
failed: %v", err) }) or move the call outside the per-iteration loop if it
shouldn’t run every iteration; apply this change for every occurrence of
store.LoadTemplates in loader_bench_test.go so errors aren’t silently ignored.

Comment on lines 643 to 646
// 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)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update method docs to describe the new error contract.

These APIs now return errors, but the comments still only describe successful behavior. Please document concrete failure modes (e.g., missing dialers / wait-group creation failure) so callers know what to handle.

Also applies to: 673-675

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/catalog/loader/loader.go` around lines 643 - 646, Update the method
comments for Store.LoadTemplates and the related LoadTemplatesWithTags to
document the new error contract: list concrete failure modes callers must handle
(e.g., missing dialers / connection setup failure, wait-group or goroutine setup
errors, template not found or path resolution failures, I/O/read/parsing errors,
and permission/OS errors), and state that the function may return a non-nil
error on these conditions instead of returning only successful results;
reference the function names Store.LoadTemplates and Store.LoadTemplatesWithTags
in the comments so callers can find the documented error cases.

@hanzhcn
Copy link
Author

hanzhcn commented Mar 4, 2026

Hi team, I understand that #6825 has already been merged for this issue. However, I'd like to highlight that our PR #7107 still provides value:

Key differences from #6825:

  1. More conservative approach: We kept Load() using logger.Fatal() for backward compatibility while fixing the core panic issue in LoadTemplates() and LoadTemplatesWithTags()
  2. Focused scope: Only updates the essential callers (lazy.go, automaticscan/util.go) without changing the public SDK API
  3. Comprehensive tests: All existing tests pass with our changes

That said, I respect the team's decision on whether to merge this or close it as superseded by #6825.

More importantly, please review our separate fix for Issue #6592 in PR #7110 - this is a critical race condition fix in the auth provider that uses sync.Once instead of atomic.Bool for proper synchronization. This fix is independent and addresses a different bug.

Thank you!

Copy link
Member

@Mzack9999 Mzack9999 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge conflict

@songfrank13141-dotcom
Copy link

Review Comments Addressed

I've addressed all the review comments from @coderabbitai[bot]. Here's a summary of the changes:

1. internal/runner/lazy.go (Line 72)

Issue: Error wrap omitted the template path
Fix: Changed errkit.Wrap(err, "failed to load template") to errkit.Wrapf(err, "failed to load template for path: %s", d.TemplatePath)

2. pkg/catalog/loader/loader.go (Lines 336-343)

Issue: Load() method called Fatal() preventing error handling in SDK/server code
Fix:

  • Added new LoadE() error method that returns errors instead of calling Fatal
  • Updated Load() to call LoadE() and convert errors to Fatal for CLI compatibility

3. pkg/catalog/loader/loader.go (Lines 643-646, 673-675)

Issue: Method docs didn't describe the new error contract
Fix: Added comprehensive documentation for LoadTemplates() and LoadTemplatesWithTags() listing all possible error cases:

  • Missing dialers / connection setup failure
  • Wait-group or goroutine setup errors
  • Template not found or path resolution failures
  • I/O, read, or parsing errors
  • Permission or OS-level errors

4. pkg/catalog/loader/loader_bench_test.go (Multiple lines)

Issue: Benchmarks were discarding errors from LoadTemplates and other methods
Fix: Updated all benchmark loops to properly handle and report errors using b.Fatalf():

  • BenchmarkStoreValidateTemplates
  • BenchmarkLoadTemplates (all 7 sub-benchmarks)
  • BenchmarkLoadTemplatesOnlyMetadata (both sub-benchmarks)

Note

I was unable to push these changes directly as I don't have write access to the hanzhcn/nuclei fork. The changes are ready in my local repository and can be pushed by the PR author or a maintainer with access.

All changes maintain backward compatibility while improving error handling throughout the template loading code path.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

Tip

For best results, initiate chat on the files or code changes.

@songfrank13141-dotcom Thank you for the detailed summary! The planned fixes look well-considered. Here's a quick assessment of each:

  1. internal/runner/lazy.go — Using errkit.Wrapf with the template path is the right call; it makes error messages actionable during debugging. ✅

  2. pkg/catalog/loader/loader.goLoadE() pattern — This is an elegant approach. Separating the error-returning LoadE() from the Load() wrapper that calls logger.Fatal() preserves backward compatibility for CLI users while giving SDK/server consumers a clean error-returning API. ✅

  3. Documentation — Adding explicit error-case documentation to LoadTemplates() and LoadTemplatesWithTags() is important since their signatures changed. ✅

  4. Benchmarks — Using b.Fatalf() instead of discarding errors is the correct testing practice. ✅

Regarding the access issue: Since you don't have write access to the hanzhcn/nuclei fork, please coordinate directly with @hanzhcn (the PR author) so they can pull in your changes and push them to the PR branch. Once the code is pushed, the review can proceed on the actual implementation.

If @hanzhcn is unavailable or unresponsive, an alternative would be to open a separate PR from your own fork targeting the same base branch (dev), referencing this PR for context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace panic with error handling in template loader when dialers are missing

4 participants