shadow1ng/fscan · error

local_pe_not_found

Error message

local_pe_not_found

What it means

WinBITSPlugin.Scan validates that the configured local PE file exists by calling os.Stat(session.Config.WinPEFile). If Stat fails (missing file, bad path, permission issue), Scan returns a failed Result with the localized message for key "local_pe_not_found". The error is raised before any BITS job is created.

Source

Thrown at plugins/local/winbits.go:32

	"github.com/shadow1ng/fscan/common/i18n"
	"github.com/shadow1ng/fscan/plugins"
)

type WinBITSPlugin struct {
	plugins.BasePlugin
}

func NewWinBITSPlugin() *WinBITSPlugin {
	return &WinBITSPlugin{BasePlugin: plugins.NewBasePlugin("winbits")}
}

func (p *WinBITSPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
	pePath := session.Config.WinPEFile
	if pePath == "" {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
	}
	if _, err := os.Stat(pePath); err != nil {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
	}

	absPath, _ := filepath.Abs(pePath)
	baseName := strings.TrimSuffix(filepath.Base(absPath), filepath.Ext(absPath))
	jobName := fmt.Sprintf("WindowsUpdate_%s", baseName)

	var output strings.Builder

	// 创建任务并提取 GUID
	out, err := exec.Command("bitsadmin", "/create", "/download", jobName).CombinedOutput()
	if err != nil {
		output.WriteString(i18n.Tr("winbits_create_task_failed", strings.TrimSpace(string(out))) + "\n")
		return &plugins.Result{Success: false, Output: output.String()}
	}

	guid := ""
	for _, line := range strings.Split(string(out), "\n") {
		if idx := strings.Index(line, "{"); idx != -1 {

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Verify the path exists on the machine running the plugin: run Test-Path <pePath> (Windows) and correct typos.
  2. Use an absolute path in WinPEFile instead of a relative path to avoid CWD dependence.
  3. Check file permissions and that the file wasn't quarantined/removed by antivirus.
  4. Confirm the correct drive/share is mounted and accessible from the scanning host.

Example fix

// before
session.Config.WinPEFile = "tools\\payload.exe" // Stat fails if CWD differs
// after
abs, _ := filepath.Abs("tools\\payload.exe")
if _, err := os.Stat(abs); err != nil {
    log.Fatalf("PE file missing: %v", err)
}
session.Config.WinPEFile = abs
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the configured PE exists before scanning
if fi, err := os.Stat(session.Config.WinPEFile); err != nil {
    return fmt.Errorf("WinPEFile %q not accessible: %w", session.Config.WinPEFile, err)
} else if fi.IsDir() {
    return fmt.Errorf("WinPEFile %q is a directory", session.Config.WinPEFile)
}

Try / catch

result := plugin.Scan(ctx, host, session)
if result != nil && !result.Success && strings.Contains(result.Error.Error(), i18n.GetText("local_pe_not_found")) {
    // correct the path in config and re-run
}

Prevention

When it happens

Trigger: os.Stat(pePath) returns an error for the non-empty WinPEFile path — file deleted/renamed, relative path resolved against a different working directory, drive letter unavailable, or no read permission on the path.

Common situations: Typo in the path, using a path that exists on the target instead of the local scanning machine (or vice versa), running from a different CWD so a relative path breaks, or antivirus quarantining the PE before the scan runs.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/92a3b59fef682ca7. Report an issue: GitHub.