kopia/kopia · error
error executing before-snapshot-root action
Error message
error executing before-snapshot-root action
What it means
uploadDirWithCheckpointing runs the policy's BeforeSnapshotRoot action (a user-configurable hook command) before reading the snapshot root. If the action command fails, the error is wrapped in a dirReadError with 'error executing before-snapshot-root action'. This is a user-defined action failing, not an internal bug — the snapshot is aborted because hooks are meant to gate the backup.
Solutions
- Run the action command manually on the host to reproduce the failure
- Fix the script: correct path, permissions, shebang, and environment (PATH, credentials)
- Temporarily remove or fix the beforeSnapshotRoot action in the policy if it's not required
- Check the action's own log output for the underlying exit reason
Example fix
// before: action references a relative path
{"actions": {"beforeSnapshotRoot": {"path": "dump-db.sh"}}}
// after: absolute path + script executes cleanly
{"actions": {"beforeSnapshotRoot": {"path": "/usr/local/bin/dump-db.sh"}}} Defensive patterns
Strategy: validation
Validate before calling
cmd := policy.EffectivePolicy().Actions.BeforeSnapshotRoot
if cmd != nil {
c := exec.CommandContext(ctx, cmd.Command, cmd.Args...)
c.Env = os.Environ()
if err := c.Run(); err != nil {
return fmt.Errorf("before-snapshot-root action will fail: %w", err)
}
} Try / catch
_, err := uploadDir(ctx, ...)
var dre dirReadError
if errors.As(err, &dre) && strings.Contains(dre.error.Error(), "before-snapshot-root") {
log.Errorf("hook failed: %v — fix or remove actions.beforeSnapshotRoot", dre.error)
return err
} Prevention
- Use absolute paths for hook scripts
- Test action commands manually under the same user/environment as the uploader
- Set a robust PATH and required env vars in the policy action
- Log and check exit codes in your scripts; fail fast with clear messages
When it happens
Trigger: A policy defines actions.beforeSnapshotRoot (e.g. a database freeze/dump script) and that command exits non-zero or cannot be started when uploadDir processes the snapshot root.
Common situations: Backup scripts referencing missing binaries or wrong paths; scripts failing due to insufficient permissions or missing DB credentials; hook scripts that work interactively but fail under the uploader's environment/PATH; SELinux/AppArmor blocking spawned commands.
Related errors
- error executing before-folder action
- a snapshot time is needed to use a path as source
- can't get local fs entry
- cannot save manifest
- checkpoint interval cannot be greater than
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/7d911ebd84fb4439.
Report an issue: GitHub.
Appendix: source
Thrown at snapshot/upload/upload.go:605
}
// uploadDirWithCheckpointing uploads the specified Directory to the repository.
func (u *Uploader) uploadDirWithCheckpointing(ctx context.Context, rootDir fs.Directory, policyTree *policy.Tree, previousDirs []fs.Directory, prototypeManifest *snapshot.Manifest) (*snapshot.DirEntry, error) {
var (
dmb snapshotfs.DirManifestBuilder
cp checkpointRegistry
)
cancelCheckpointer := u.periodicallyCheckpoint(ctx, &cp, prototypeManifest)
defer cancelCheckpointer()
var hc actionContext
localDirPathOrEmpty := rootDir.LocalFilesystemPath()
overrideDir, err := u.executeBeforeFolderAction(ctx, "before-snapshot-root", policyTree.EffectivePolicy().Actions.BeforeSnapshotRoot, localDirPathOrEmpty, &hc)
if err != nil {
return nil, dirReadError{errors.Wrap(err, "error executing before-snapshot-root action")}
}
defer u.executeAfterFolderAction(ctx, "after-snapshot-root", policyTree.EffectivePolicy().Actions.AfterSnapshotRoot, localDirPathOrEmpty, &hc)
p := &policyTree.EffectivePolicy().OSSnapshotPolicy
switch mode := osSnapshotMode(p); mode {
case policy.OSSnapshotNever:
case policy.OSSnapshotAlways, policy.OSSnapshotWhenAvailable:
if overrideDir != nil {
rootDir = overrideDir
}
switch osSnapshotDir, cleanup, err := createOSSnapshot(ctx, rootDir, p); {
case err == nil:
defer cleanup()
overrideDir = osSnapshotDirView on GitHub (pinned to 82495e54b5)