{"record":{"id":"d7ba4e722f8332e3","repo":"hasura/graphql-engine","slug":"cannot-write-metadata-to-project-w","errorCode":null,"errorMessage":"cannot write metadata to project: %w","messagePattern":"cannot write metadata to project: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/commands/metadata_handlers.go","lineNumber":50,"sourceCode":"}\n\ntype metadataModeDirectoryHandler struct{}\n\nfunc (m *metadataModeDirectoryHandler) Export(o *MetadataExportOptions) error {\n\tvar op errors.Op = \"commands.metadataModeDirectoryHandler.Export\"\n\n\tmetadataHandler := projectmetadata.NewHandlerFromEC(o.EC)\n\tfiles, err := metadataHandler.ExportMetadata()\n\n\to.EC.Spinner.Stop()\n\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"failed to export metadata: %w\", err))\n\t}\n\n\terr = metadataHandler.WriteMetadata(files)\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"cannot write metadata to project: %w\", err))\n\t}\n\n\treturn nil\n}\n\nfunc (m *metadataModeDirectoryHandler) Apply(o *MetadataApplyOptions) error {\n\tvar op errors.Op = \"commands.metadataModeDirectoryHandler.Apply\"\n\n\tmetadataHandler := projectmetadata.NewHandlerFromEC(o.EC)\n\tif !o.DryRun {\n\t\tif o.EC.Config.Version == cli.V2 {\n\t\t\t_, err := metadataHandler.V1ApplyMetadata()\n\t\t\tif err != nil {\n\t\t\t\treturn errors.E(op, errorApplyingMetadata(err))\n\t\t\t}\n\n\t\t\to.EC.Logger.Debug(\"metadata applied using v1 replace_metadata\")\n\t\t} else {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/commands/metadata_handlers.go#L32-L68","documentation":"After a successful server export in directory mode, writing the metadata files into the project via metadataHandler.WriteMetadata failed, and that failure is wrapped as 'cannot write metadata to project'. This is a local filesystem error class — the server interaction already succeeded.","triggerScenarios":"`hasura metadata export` where the metadata directory (or files/databases subdirectories) cannot be written: permission denied, read-only filesystem, path conflicts with an existing file where a directory is expected, or disk full.","commonSituations":"Running the CLI in Docker/CI without write permissions on the mounted project, a file named 'metadata' occupying the directory path, SELinux/AppArmor denials, or full disks.","solutions":["Check write permissions on the project's metadata directory: chmod/adjust ownership as needed","Remove any regular file blocking creation of the metadata directory tree","Ensure the project volume is mounted read-write in containers","Free disk space if the wrapped error shows ENOSPC"],"exampleFix":"# before (file blocking the directory)\n./metadata  # a regular file\n# after\nrm ./metadata && hasura metadata export","handlingStrategy":"validation","validationCode":"# Shell: verify writability and no file/dir conflicts\n[ ! -f metadata ] || { echo \"'metadata' is a file, not a dir\"; exit 1; }\nmkdir -p metadata && touch metadata/.probe && rm metadata/.probe","typeGuard":"// Go\nfunc canWriteMetadataDir(root string) bool {\n  dir := filepath.Join(root, \"metadata\")\n  if info, err := os.Stat(dir); err == nil && !info.IsDir() {\n    return false\n  }\n  return os.MkdirAll(dir, 0o755) == nil\n}","tryCatchPattern":null,"preventionTips":["Mount project volumes read-write in containers","Never create a regular file named 'metadata' in the project root","Grant the CLI user write permission on the metadata tree"],"tags":["filesystem","metadata-export","permissions"],"backgroundTag":"write-permission-denied","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}