{"record":{"id":"09f8ed8a46587a25","repo":"micro-editor/micro","slug":"cannot-save-readonly-buffer","errorCode":null,"errorMessage":"Cannot save readonly buffer","messagePattern":"Cannot save readonly buffer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/buffer/save.go","lineNumber":235,"sourceCode":"}\n\n// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist\nfunc (b *Buffer) SaveAs(filename string) error {\n\treturn b.saveToFile(filename, false, false)\n}\n\nfunc (b *Buffer) SaveWithSudo() error {\n\treturn b.SaveAsWithSudo(b.Path)\n}\n\nfunc (b *Buffer) SaveAsWithSudo(filename string) error {\n\treturn b.saveToFile(filename, true, false)\n}\n\nfunc (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error {\n\tvar err error\n\tif b.Type.Readonly {\n\t\treturn errors.New(\"Cannot save readonly buffer\")\n\t}\n\tif b.Type.Scratch {\n\t\treturn errors.New(\"Cannot save scratch buffer\")\n\t}\n\n\tif withSudo {\n\t\t_, err := exec.LookPath(config.GlobalSettings[\"sucmd\"].(string))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !autoSave && b.Settings[\"rmtrailingws\"].(bool) {\n\t\tfor i, l := range b.lines {\n\t\t\tleftover := util.CharacterCount(bytes.TrimRightFunc(l.data, unicode.IsSpace))\n\n\t\t\tlinelen := util.CharacterCount(l.data)\n\t\t\tb.Remove(Loc{leftover, i}, Loc{linelen, i})","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/micro-editor/micro/blob/1c8b82b32e408a5faf340039ed92d5266bea3293/internal/buffer/save.go#L217-L253","documentation":"Returned by (*Buffer).saveToFile (internal/buffer/save.go:235) — the common backend of Save, SaveAs, SaveWithSudo — when b.Type.Readonly is true. This is about the buffer *type* (BTLog, and other internal readonly types like the help buffer family), not file permissions: type-level readonly buffers are viewer-only by design and every save variant refuses them.","triggerScenarios":"Pressing Ctrl-s or running :w / :save while focused on the > log pane, a help page, or any plugin-created buffer whose BufType has Readonly set; also SaveAs on such a buffer hits the same check because SaveAs routes through saveToFile.","commonSituations":"Users trying to annotate the log or help text and hitting save; plugins spawning readonly buffers for reports and offering a save keybinding that then errors.","solutions":["Select-all and copy the content, then open a normal buffer (Ctrl-t new / :open newfile), paste, and save that buffer","If it's your own plugin buffer and saving should work, construct it with a writable BufType (BTDefault/BTScratch per intent) instead of a Readonly one","Recognize the context: help/log panes are ephemeral viewers — nothing is lost by not saving"],"exampleFix":"// before (plugin creating a viewer buffer users then try to save)\nbuf := buffer.NewBufferFromString(report, \"report\", buffer.BTLog)\n\n// after: make it a savable scratch/default buffer\nbuf := buffer.NewBufferFromString(report, \"report\", buffer.BTDefault)","handlingStrategy":"validation","validationCode":"// Only offer save for writable buffer types\nfunc savable(b *buffer.Buffer) bool {\n    return !b.Type.Readonly && !b.Type.Scratch\n}\nif savable(h.Buf) {\n    h.Save()\n} else {\n    InfoBar.Message(\"viewer buffer — copy content to a file buffer to save\")\n}","typeGuard":null,"tryCatchPattern":"if err := h.Buf.Save(); err != nil {\n    if err.Error() == \"Cannot save readonly buffer\" {\n        InfoBar.Error(\"this pane (help/log) is read-only; nothing was lost\")\n        return // intentional design; do not retry with SaveAs — same check applies\n    }\n    return err\n}","preventionTips":["Check focus before reflexive Ctrl-s: help and log panes cannot save","Plugins: choose BufType by intent — viewers get Readonly, drafts get BTDefault","SaveAs will not bypass this; only moving text to a normal buffer will"],"tags":["save","readonly","buffer-type","log","help"],"backgroundTag":null,"analyzedSha":"1c8b82b32e408a5faf340039ed92d5266bea3293","analyzedAt":"2026-08-15T20:01:45.134Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}