{"record":{"id":"89ff4d53362d914b","repo":"micro-editor/micro","slug":"cannot-save-scratch-buffer","errorCode":null,"errorMessage":"Cannot save scratch buffer","messagePattern":"Cannot save scratch buffer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/buffer/save.go","lineNumber":238,"sourceCode":"func (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})\n\t\t}\n\n\t\tb.RelocateCursors()","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/micro-editor/micro/blob/1c8b82b32e408a5faf340039ed92d5266bea3293/internal/buffer/save.go#L220-L256","documentation":"Returned by (*Buffer).saveToFile (internal/buffer/save.go:238) when b.Type.Scratch is true. Scratch buffers (help pages, command output like plugin-search results, and other internal ephemeral panes) have no backing file identity; refusing the save keeps them from corrupting disk state. Like [17] it guards every save variant including SaveAs.","triggerScenarios":"Running :w, Ctrl-s, or :save while a help page or a scratch command-output buffer (e.g. the plugin manager listing) is the active pane.","commonSituations":"Split layout where a help/scratch pane keeps focus and the user reflexively saves; plugins that map a global save key and don't filter buffer types.","solutions":["Move focus back to a file buffer (Ctrl-w / tab switching) before saving","To persist scratch content: copy it into a new file buffer (:open /tmp/notes, paste, save)","Plugin authors: use a non-scratch type if persistence is intended, or wire save to serialize the content yourself"],"exampleFix":"// before\n// active pane: Help keybindings\nCtrl-s  ->  Cannot save scratch buffer\n\n// after\n// copy text (Ctrl-a Ctrl-c), then\n:open ~/notes.md   // paste (Ctrl-v) and Ctrl-s","handlingStrategy":"validation","validationCode":"// Filter global save bindings by buffer type\nif h.Buf.Type.Scratch || h.Buf.Type.Readonly {\n    InfoBar.Message(\"scratch pane has no file — copy to a new buffer to persist\")\n    return\n}\nh.Save()","typeGuard":null,"tryCatchPattern":"if err := h.Buf.Save(); err != nil {\n    switch err.Error() {\n    case \"Cannot save scratch buffer\":\n        InfoBar.Error(\"scratch buffer: select-all, copy, then :open <file> and paste\")\n        return\n    case \"Cannot save readonly buffer\":\n        InfoBar.Error(err)\n        return\n    }\n    return err\n}","preventionTips":["Switch pane focus (Ctrl-w/tab) back to a file buffer before saving","Remember the usual save-name prompt only appears for normal unnamed buffers, not scratch","Plugin authors: mark report panes scratch so users get this clear refusal instead of stray files"],"tags":["save","scratch","buffer-type","help","plugin"],"backgroundTag":null,"analyzedSha":"1c8b82b32e408a5faf340039ed92d5266bea3293","analyzedAt":"2026-08-15T20:01:45.134Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}