{"record":{"id":"dc65b61b3f0f31b5","repo":"pocketbase/pocketbase","slug":"failed-to-save-migration-file-q-v","errorCode":null,"errorMessage":"failed to save migration file %q: %v","messagePattern":"failed to save migration file %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/migratecmd/migratecmd.go","lineNumber":186,"sourceCode":"\t\tvar templateErr error\n\t\tif p.config.TemplateLang == TemplateLangJS {\n\t\t\ttemplate, templateErr = p.jsBlankTemplate()\n\t\t} else {\n\t\t\ttemplate, templateErr = p.goBlankTemplate()\n\t\t}\n\t\tif templateErr != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to resolve create template: %v\", templateErr)\n\t\t}\n\t}\n\n\t// ensure that the migrations dir exist\n\tif err := os.MkdirAll(dir, os.ModePerm); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// save the migration file\n\tif err := os.WriteFile(resultFilePath, []byte(template), 0644); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to save migration file %q: %v\", resultFilePath, err)\n\t}\n\n\tif interactive {\n\t\tfmt.Printf(\"Successfully created file %q\\n\", resultFilePath)\n\t}\n\n\treturn filename, nil\n}\n\nfunc (p *plugin) migrateCollectionsHandler(args []string, interactive bool) (string, error) {\n\tcreateArgs := []string{\"collections_snapshot\"}\n\tcreateArgs = append(createArgs, args...)\n\n\tcollections := []*core.Collection{}\n\tif err := p.app.CollectionQuery().OrderBy(\"created ASC\").All(&collections); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to fetch migrations list: %v\", err)\n\t}\n","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/pocketbase/pocketbase/blob/5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457/plugins/migratecmd/migratecmd.go#L168-L204","documentation":"Returned by migratecmd's migrateCreateHandler (plugins/migratecmd/migratecmd.go:186) when os.WriteFile fails to persist the newly generated migration file at resultFilePath. The migrations dir was just ensured via MkdirAll, so failures are file-level: permission denied, disk full, existing read-only file with the same timestamped name, or invalid path characters on the host OS.","triggerScenarios":"Executing `./pocketbase migrate create` or `migrate collections` when the process cannot write into the migrations dir; a same-named file already exists and is read-only; disk exhaustion; running as non-root against a root-owned pb_migrations.","commonSituations":"Developers running the CLI with sudo once (files become root-owned) and later without; CI containers with size-limited writable layers; filenames containing characters rejected by Windows (e.g. ':' from a clock-formatted name).","solutions":["Retry after fixing ownership/permissions of the migrations dir: `chown -R $(id -u) pb_migrations && chmod -R u+rwX pb_migrations`.","Free disk space or raise the container writable-layer limit.","Remove or chmod the pre-existing read-only file that collides with the generated name.","Run the CLI as the same user that owns the application files, never mix sudo and non-sudo invocations."],"exampleFix":"# before: root-owned migration files from a sudo run\n$ sudo ./pocketbase migrate create add_posts\n$ ./pocketbase migrate create add_users  # fails to write\n\n# after: unify ownership, then run unprivileged\n$ sudo chown -R $USER pb_migrations\n$ ./pocketbase migrate create add_users","handlingStrategy":"validation","validationCode":"// Verify the target file path is writable before invoking migrate create.\nfunc migrationPathWritable(dir, filename string) bool {\n    target := filepath.Join(dir, filename)\n    if info, err := os.Stat(target); err == nil && info.Mode().Perm()&0o200 == 0 {\n        return false // existing read-only collision\n    }\n    return dirWritable(dir) // reuse the CreateTemp probe from error 228\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run the pocketbase CLI as the user owning pb_migrations (no sudo for one run, plain user the next).","Add a pre-command `chmod -R u+rwX pb_migrations` to deployment scripts.","Keep collection/migration names free of characters invalid on Windows (':', '?', '*').","Watch disk space in CI containers where migrations are generated."],"tags":["go","pocketbase","migratecmd","cli","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457","analyzedAt":"2026-08-15T10:06:33.165Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}