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

  1. Run the action command manually on the host to reproduce the failure
  2. Fix the script: correct path, permissions, shebang, and environment (PATH, credentials)
  3. Temporarily remove or fix the beforeSnapshotRoot action in the policy if it's not required
  4. 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

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


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 = osSnapshotDir

View on GitHub (pinned to 82495e54b5)