{"record":{"id":"84fb93139a1637d1","repo":"hashicorp/terraform","slug":"error-saving-plugin-dir-to-workspace-directory","errorCode":null,"errorMessage":"Error saving -plugin-dir to workspace directory: %s","messagePattern":"Error saving -plugin-dir to workspace directory: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/init_run.go","lineNumber":55,"sourceCode":"\tc.Meta.input = initArgs.InputEnabled\n\tc.Meta.targetFlags = initArgs.TargetFlags\n\tc.Meta.compactWarnings = initArgs.CompactWarnings\n\n\t// Copying the state only happens during backend migration, so setting\n\t// -force-copy implies -migrate-state\n\tif c.forceInitCopy {\n\t\tc.migrateState = true\n\t}\n\n\tif len(initArgs.PluginPath) > 0 {\n\t\tc.pluginPath = initArgs.PluginPath\n\t}\n\n\t// Get the working directory\n\tpath := c.Meta.WorkingDir.RootModuleDir()\n\n\tif err := c.storePluginPath(c.pluginPath); err != nil {\n\t\tdiags = diags.Append(fmt.Errorf(\"Error saving -plugin-dir to workspace directory: %s\", err))\n\t\tview.Diagnostics(diags)\n\t\treturn 1\n\t}\n\n\t// Initialization can be aborted by interruption signals\n\tctx, done := c.InterruptibleContext(c.CommandContext())\n\tdefer done()\n\n\tif initArgs.FromModule != \"\" {\n\t\tsrc := initArgs.FromModule\n\n\t\tempty, err := configs.IsEmptyDir(path, initArgs.TestsDirectory)\n\t\tif err != nil {\n\t\t\tdiags = diags.Append(fmt.Errorf(\"Error validating destination directory: %s\", err))\n\t\t\tview.Diagnostics(diags)\n\t\t\treturn 1\n\t\t}\n\t\tif !empty {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/init_run.go#L37-L73","documentation":"Emitted by InitCommand.run when c.storePluginPath(c.pluginPath) returns an error while persisting the -plugin-dir flag value into the workspace's data directory. The %s carries the underlying write error. This happens very early in init, before any backend or provider work, so the command exits immediately with code 1.","triggerScenarios":"Running `terraform init -plugin-dir=<dir>` when Terraform cannot write the plugin-path marker file (typically under .terraform/) into the working directory. Causes: working directory read-only or on a read-only mount, .terraform owned by another user, disk full, or the path contains characters the OS rejects.","commonSituations":"Read-only source trees (e.g. terraform run from a mounted/checked-out directory without write permission); containers where the working dir is bind-mounted read-only; .terraform created by root and init re-run as non-root; full disk; NFS mounts with permission issues.","solutions":["Ensure the working directory (and .terraform if present) is writable by the terraform process: `chmod -R u+w .` or `chown` appropriately.","Remove a stale/foreign .terraform directory: `rm -rf .terraform` and retry init.","Free disk space if the volume is full.","If the tree must stay read-only, point terraform at a writable data dir or run init from a writable checkout."],"exampleFix":"# before\n$ terraform init -plugin-dir=/opt/plugins   # ./.terraform read-only\n# after\n$ sudo chown -R $USER .terraform\n$ terraform init -plugin-dir=/opt/plugins","handlingStrategy":"validation","validationCode":"// Verify the working dir and .terraform are writable before init -plugin-dir.\nif fi, err := os.Stat(wd); err != nil || fi.Mode().Perm()&0200 == 0 {\n    return fmt.Errorf(\"working dir %q not writable; cannot persist plugin path\", wd)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run init from a writable checkout, not a read-only mount.","Own the .terraform directory across runs (same UID).","Remove stale .terraform directories before re-initializing in CI."],"tags":["terraform-init","plugin-dir","filesystem","permissions","write"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}