{"record":{"id":"7d911ebd84fb4439","repo":"kopia/kopia","slug":"error-executing-before-snapshot-root-action","errorCode":null,"errorMessage":"error executing before-snapshot-root action","messagePattern":"error executing before-snapshot-root action","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"snapshot/upload/upload.go","lineNumber":605,"sourceCode":"}\n\n// uploadDirWithCheckpointing uploads the specified Directory to the repository.\nfunc (u *Uploader) uploadDirWithCheckpointing(ctx context.Context, rootDir fs.Directory, policyTree *policy.Tree, previousDirs []fs.Directory, prototypeManifest *snapshot.Manifest) (*snapshot.DirEntry, error) {\n\tvar (\n\t\tdmb snapshotfs.DirManifestBuilder\n\t\tcp  checkpointRegistry\n\t)\n\n\tcancelCheckpointer := u.periodicallyCheckpoint(ctx, &cp, prototypeManifest)\n\tdefer cancelCheckpointer()\n\n\tvar hc actionContext\n\n\tlocalDirPathOrEmpty := rootDir.LocalFilesystemPath()\n\n\toverrideDir, err := u.executeBeforeFolderAction(ctx, \"before-snapshot-root\", policyTree.EffectivePolicy().Actions.BeforeSnapshotRoot, localDirPathOrEmpty, &hc)\n\tif err != nil {\n\t\treturn nil, dirReadError{errors.Wrap(err, \"error executing before-snapshot-root action\")}\n\t}\n\n\tdefer u.executeAfterFolderAction(ctx, \"after-snapshot-root\", policyTree.EffectivePolicy().Actions.AfterSnapshotRoot, localDirPathOrEmpty, &hc)\n\n\tp := &policyTree.EffectivePolicy().OSSnapshotPolicy\n\n\tswitch mode := osSnapshotMode(p); mode {\n\tcase policy.OSSnapshotNever:\n\tcase policy.OSSnapshotAlways, policy.OSSnapshotWhenAvailable:\n\t\tif overrideDir != nil {\n\t\t\trootDir = overrideDir\n\t\t}\n\n\t\tswitch osSnapshotDir, cleanup, err := createOSSnapshot(ctx, rootDir, p); {\n\t\tcase err == nil:\n\t\t\tdefer cleanup()\n\n\t\t\toverrideDir = osSnapshotDir","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/snapshot/upload/upload.go#L587-L623","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: action references a relative path\n{\"actions\": {\"beforeSnapshotRoot\": {\"path\": \"dump-db.sh\"}}}\n// after: absolute path + script executes cleanly\n{\"actions\": {\"beforeSnapshotRoot\": {\"path\": \"/usr/local/bin/dump-db.sh\"}}}","handlingStrategy":"validation","validationCode":"cmd := policy.EffectivePolicy().Actions.BeforeSnapshotRoot\nif cmd != nil {\n    c := exec.CommandContext(ctx, cmd.Command, cmd.Args...)\n    c.Env = os.Environ()\n    if err := c.Run(); err != nil {\n        return fmt.Errorf(\"before-snapshot-root action will fail: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"_, err := uploadDir(ctx, ...)\nvar dre dirReadError\nif errors.As(err, &dre) && strings.Contains(dre.error.Error(), \"before-snapshot-root\") {\n    log.Errorf(\"hook failed: %v — fix or remove actions.beforeSnapshotRoot\", dre.error)\n    return err\n}","preventionTips":["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"],"tags":["policy-actions","hook","snapshot"],"backgroundTag":"hook-command-failed","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}