{"record":{"id":"208aabe1a66eb890","repo":"derailed/k9s","slug":"osc52-clipboard-unavailable-stdout-is-not-a-tty-o","errorCode":null,"errorMessage":"osc52 clipboard unavailable: stdout is not a tty or TERM=dumb","messagePattern":"osc52 clipboard unavailable: stdout is not a tty or TERM=dumb","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/view/clipboard.go","lineNumber":91,"sourceCode":"func termValue() string {\n\treturn strings.ToLower(strings.TrimSpace(os.Getenv(termEnv)))\n}\n\nfunc isTTY(f *os.File) bool {\n\tif f == nil {\n\t\treturn false\n\t}\n\tfi, err := f.Stat()\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn fi.Mode()&os.ModeCharDevice != 0\n}\n\nfunc writeOSC52(text string) error {\n\tif !canTryOSC52() {\n\t\treturn fmt.Errorf(\"osc52 clipboard unavailable: stdout is not a tty or TERM=dumb\")\n\t}\n\n\tencoded := base64.StdEncoding.EncodeToString([]byte(text))\n\tmaxLen := osc52MaxEncodedLen()\n\tif len(encoded) > maxLen {\n\t\treturn fmt.Errorf(\"osc52 payload exceeds encoded size limit (%d > %d)\", len(encoded), maxLen)\n\t}\n\n\tterm := termValue()\n\tseq := osc52Sequence(encoded, os.Getenv(tmuxEnv) != \"\", strings.HasPrefix(term, screenTermPrefix))\n\t_, err := os.Stdout.WriteString(seq)\n\n\treturn err\n}\n\nfunc osc52MaxEncodedLen() int {\n\tv := strings.TrimSpace(os.Getenv(osc52MaxEnv))\n\tif v == \"\" {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/view/clipboard.go#L73-L109","documentation":"OSC52 clipboard copy (terminal escape-sequence clipboard) was attempted, but canTryOSC52() found stdout is not a character device or TERM=dumb. OSC52 works only when output goes to a real terminal that supports the escape sequence; piped output or dumb terminals cannot host a clipboard.","triggerScenarios":"Running the TUI with stdout piped/redirected (k9s | tee log), inside wrappers that allocate a pty incorrectly, or with TERM=dumb set. Also when the process is spawned by an IDE task/CI without a tty.","commonSituations":"CI or scripted runs invoking the binary; debugging with output redirection; environments where TERM is unset and defaults to dumb; some CI-injected shells.","solutions":["Run in a real terminal without piping stdout; unset TERM=dumb (export TERM=xterm-256color or similar).","Prefer the system clipboard integration: install xclip/xsel (Linux), pbcopy (macOS), or wl-copy (Wayland) so the app can shell out instead of OSC52.","Inside tmux/screen, make sure TERM is set to the inner terminal's value (tmux-256color) so detection passes.","If scripting, skip clipboard features: avoid the copy keybindings or run a non-interactive subcommand."],"exampleFix":"// before: OSC52 only\nif err := writeOSC52(text); err != nil { flash.Err(err) }\n\n// after: fall back to system clipboard tool\nif err := writeOSC52(text); err != nil {\n    if err2 := writeExternalClipboard(text); err2 != nil {\n        flash.Err(err2)\n    }\n}","handlingStrategy":"fallback","validationCode":"if !canTryOSC52() {\n    if err := writeExternalClipboard(text); err != nil {\n        return fmt.Errorf(\"no clipboard available (osc52 and system tool both failed): %w\", err)\n    }\n    return nil\n}\nreturn writeOSC52(text)","typeGuard":"func hasTTYClipboard() bool {\n    if strings.TrimSpace(os.Getenv(termEnv)) == dumbTerm { return false }\n    fi, err := os.Stdout.Stat()\n    return err == nil && fi.Mode()&os.ModeCharDevice != 0\n}","tryCatchPattern":"if err := writeOSC52(text); err != nil {\n    if strings.Contains(err.Error(), \"osc52 clipboard unavailable\") {\n    copyViaSystemTool(text) // xclip/pbcopy/wl-copy fallback\n    }\n}","preventionTips":["Install a system clipboard binary so the app has a non-tty path.","Never run interactive sessions with stdout piped; redirect logs elsewhere.","Set TERM to a real terminal value; avoid TERM=dumb."],"tags":["terminal","clipboard","osc52","environment"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}