yorukot/superfile · error
cannot spawn process : %w
Error message
cannot spawn process : %w
What it means
zipSources wraps a failure from processBar.SendAddProcessMsg when it tries to register a new compression process entry in the progress-bar model. The compression never starts because the progress tracking infrastructure could not spawn the process record.
Source
Thrown at src/internal/file_operations_compress.go:91
totalFiles, err := validateCompressOperation(filesToCompress)
if err != nil {
return NewNotifyModalMsg(notify.New(true, "Invalid file/dir to compress", err.Error(), notify.NoAction),
reqID)
}
if err := zipSources(filesToCompress, totalFiles, zipPath, &m.processBarModel); err != nil {
slog.Error("Error in zipping files", "error", err)
return NewCompressOperationMsg(processbar.Failed, reqID)
}
return NewCompressOperationMsg(processbar.Successful, reqID)
}
}
func zipSources(sources []string, totalFiles int, target string, processBar *processbar.Model) error {
var err error
p, err := processBar.SendAddProcessMsg(filepath.Base(target), processbar.OpCompress, totalFiles, true)
if err != nil {
return fmt.Errorf("cannot spawn process : %w", err)
}
_, err = os.Stat(target)
if err == nil {
p.ErrorMsg = "File already exists"
p.State = processbar.Cancelled
p.DoneTime = time.Now()
pSendErr := processBar.SendUpdateProcessMsg(p, true)
if pSendErr != nil {
slog.Error("Error sending process update", "error", pSendErr)
}
return errors.New("file already exists")
}
f, err := os.Create(target)
if err != nil {
return err
}
defer f.Close()View on GitHub (pinned to b72f550bc6)
Solutions
- Ensure the processbar.Model is initialized and its event loop is running before calling zipSources.
- Check application shutdown ordering: cancel compressions before closing the TUI.
- Recover the wrapped cause with errors.Unwrap/errors.As to see the underlying send failure.
- Retry the operation with a fresh processbar.Model if the previous one was closed.
Example fix
// before
p, err := processBar.SendAddProcessMsg(filepath.Base(target), processbar.OpCompress, totalFiles, true)
if err != nil {
return fmt.Errorf("cannot spawn process : %w", err)
}
// after
select {
case <-done: // UI shutting down
return fmt.Errorf("compression cancelled: UI shutting down")
default:
}
p, err := processBar.SendAddProcessMsg(filepath.Base(target), processbar.OpCompress, totalFiles, true)
if err != nil {
return fmt.Errorf("cannot spawn process : %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the progress model is alive before starting
if processBar == nil || shuttingDown {
return fmt.Errorf("progress UI not available")
} Try / catch
if err := ops.ZipSources(sources, total, target, processBar); err != nil {
if strings.Contains(err.Error(), "cannot spawn process") {
// recreate processbar.Model and retry, or run without progress UI
}
return err
} Prevention
- Initialize the processbar.Model before starting compression jobs.
- Cancel in-flight compressions during UI shutdown, not after.
- Don't reuse a closed/finished processbar.Model instance.
When it happens
Trigger: Calling zipSources with a processbar.Model whose message channel is closed/unavailable, the TUI is shutting down, or the internal message send fails (e.g. model not initialized or already terminated).
Common situations: Starting a compression while the UI is exiting; reusing a finished/closed processbar.Model; race between UI teardown and a queued compression job.
Related errors
- source path does not exist: %s
- cannot access source path %s: %w
- the file is not readable: %s
- error while counting files for %s: %s
- failed to get absolute path of the first path: %w
AI-assisted analysis of yorukot/superfile@b72f550bc6 (2026-09-01).
Data as JSON: /api/errors/6b06920ecfda9e07.
Report an issue: GitHub.