{"record":{"id":"1892f434c3a8b6ef","repo":"goreleaser/goreleaser","slug":"node-write-sea-config-json-w","errorCode":null,"errorMessage":"node: write sea-config.json: %w","messagePattern":"node: write sea-config\\.json: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/builders/node/sea.go","lineNumber":50,"sourceCode":"\t\treturn fmt.Errorf(\"node: abs build dir %q: %w\", build.Dir, err)\n\t}\n\n\tcfg, err := buildSEAConfigJSON(\n\t\tabsBuildDir,\n\t\tabsMainPath,\n\t\ttargetNode,\n\t\toutput,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgBytes, err := json.MarshalIndent(cfg, \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(name, cfgBytes, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"node: write sea-config.json: %w\", err)\n\t}\n\treturn nil\n}\n\n// buildSEAConfigJSON renders the sea-config.json contents goreleaser\n// will hand to `node --build-sea`. Starts from the user's\n// sea-config.json in buildDir (if any), then forces the\n// goreleaser-owned fields and rewrites relative `assets` paths to be\n// absolute relative to buildDir so they survive the move into the\n// dist directory.\nfunc buildSEAConfigJSON(buildDir, mainPath, targetNode, output string) (map[string]any, error) {\n\tcfg, err := loadUserSEAConfig(buildDir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcfg[\"main\"] = mainPath\n\tcfg[\"output\"] = output","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/goreleaser/goreleaser/blob/f5edd7395693c0c6b501dc722d445d2e86af854d/internal/builders/node/sea.go#L32-L68","documentation":"This error wraps the failure of os.WriteFile when GoReleaser tries to write the generated sea-config.json into the build directory during Node.js Single Executable Application (SEA) builds. The config file is what goreleaser later hands to `node --build-sea`, so if it cannot be written the SEA build cannot proceed. The wrapped %w preserves the underlying OS error (permissions, disk full, missing directory).","triggerScenarios":"os.WriteFile(name, cfgBytes, 0o600) fails inside createSEAConfig (called from Build): e.g. the build directory does not exist, the process lacks write permission on it, or the disk is full.","commonSituations":"Building in a read-only CI workspace or one where a previous step deleted the dist/build directory; running goreleaser as a non-root user against a root-owned directory; a read-only container filesystem; disk quota exhaustion.","solutions":["Check the underlying wrapped error (printed after 'node: write sea-config.json:') to see if it is ENOENT, EACCES, or ENOSPC and fix accordingly.","Ensure the build directory (build.Dir) exists and is writable by the user running goreleaser before the build.","Free disk space or raise quota if the error is no-space-left-on-device.","Do not run the build from a read-only mount; adjust volume/container permissions."],"exampleFix":"// before: building inside a root-owned directory\n// $ goreleaser build  -> node: write sea-config.json: open ...: permission denied\n// after: make the workspace writable\n$ sudo chown -R $(whoami) ./dist\n$ goreleaser build","handlingStrategy":"validation","validationCode":"const dir = './dist';\ntry {\n  await fs.access(dir, fs.constants.W_OK);\n} catch {\n  throw new Error(`build dir ${dir} missing or not writable`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the build/dist directory exists and is writable before running goreleaser.","Avoid read-only mounts for the build workspace in CI/containers.","Monitor disk space; fail fast on low-space conditions.","Run builds as a user that owns the workspace."],"tags":["node","sea","filesystem","goreleaser"],"backgroundTag":"file-write-permission-denied","analyzedSha":"f5edd7395693c0c6b501dc722d445d2e86af854d","analyzedAt":"2026-09-05T09:57:18.807Z","contentChangedAt":"2026-09-05T09:57:18.807Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}