2026-08-03

"'xterm-ghostty': Unknown Terminal Type"

The command was clear. Five letters. It has worked since before I enlisted. Here is what the server said back:


'xterm-ghostty': unknown terminal type.

I would like to tell you I shrugged and moved on. I did not. I am tech's bitch, and tonight tech wanted me to learn about terminfo databases.

It's never just clear

First lesson: when a terminal type is unknown, it is not one command that breaks. It is every curses program. top — broken. nano — broken. less — broken. vim — broken. tput — broken, which is extra funny because tput is the tool you'd use to diagnose the others. The entire full-screen half of Unix just walks off the job at once, like it unionized while I was in the other room.

The cause is mundane. I use Ghostty as my terminal, which announces itself as xterm-ghostty. The server is a fresh Ubuntu box whose ncurses database was frozen before Ghostty existed. The server has simply never heard of my terminal. It's not hostile. It's a bouncer checking a list printed last year.

The fix, once you know it, is one genuinely beautiful pipe:


infocmp -x xterm-ghostty | ssh root@host 'tic -x -'

Export the terminal's description from the machine that has it, compile it on the machine that doesn't. One line. The terminal literally introduces itself to the server. I felt like a wizard for about ninety seconds.

Then I made the mistake of looking around the shell config while I was in there.

The alias that was impersonating dd

In the rc file, I found this: dd was aliased to a directory lister. Some helper from years past — list dirs, cute name, whatever. Except dd is already a program. It is the program. dd(1) writes raw blocks to disks. It is the command whose man page might as well open with a chaplain's blessing.

So for who knows how long, this box had a dd that harmlessly listed directories — right up until some script, or some future me in a hurry, ran it in a context where the alias didn't apply, and got the real one. Commands that can destroy disks should not be surprises. The lister got renamed. The real dd got its name back. If I'm going to zero a drive, I want to do it on purpose, with both eyes open, the way the Marine Corps taught me to do dangerous things.

Also in the file: a disk-usage helper called du1 that walked all of / — including /proc, /sys, and the network mounts — then sorted the output ascending, so after a five-minute crawl through the plumbing of the operating system, the answer you actually wanted was helpfully at the very bottom. It was a tool designed by someone who hated the person who would use it, and that person was me, and the someone was also me.

That's not a prompt, that's a clock

The prompt on this server showed the date and the time. That's it. No user. No hostname. No directory. Which means every SSH session looked identical to every other SSH session, which is exactly how commands get executed on the wrong server. I had a chain of command in the Corps; the prompt is the chain of command of a shell, and this one was a private with no name tape.

New prompt: exit code when the last command failed, user@host, current directory, git branch — and the hostname turns red when you're root. Red means you are holding a loaded weapon. This is not decoration. This is a range flag.

While I was at it: rm is now trash-put on that box, per the house standing order — recoverable beats gone. The real rm survives as rm!, because sometimes you do mean it, and the exclamation point makes you say so.

And then my fix bit me

Sourced the new rc file. Syntax error. On du1() { — my own function.

The reason is a genuine bash landmine: aliases are expanded before a same-named function definition is parsed. Any shell still holding the old alias du1=... would take my clean function definition and macro-expand it into garbage before the parser ever saw it. The fix I shipped was broken specifically in shells that needed the fix.

The file now opens with unalias for every converted name. And I verified it the only way that counts — I deliberately reproduced the exact stale-alias session and sourced the file into it. It held.

Epilogue: the pipe that lied

Nine days later, the beautiful one-line terminfo fix turned out to be a silent no-op on two servers. On the Mac, infocmp needs TERMINFO_DIRS pointed at Ghostty's app bundle — without it, the export produces an empty pipe. And tic, given empty stdin, succeeds. Says nothing. Reports nothing. A failed export piped into a remote compile impersonates a successful install perfectly.

The pipe was beautiful. The pipe was also lying to me. Standard relationship.

The rule that came out of it: never trust the pipe — run TERM=xterm-ghostty tput clear on the target and watch the screen actually clear. Both servers got re-pushed and verified for real this time. The entry now also lives in ~/.terminfo on the laptop itself, because it turned out nested shells could break it locally too, and I refuse to lose a land war against my own terminal on my own machine.

Total cost of clearing one screen: one evening, one impersonated disk destroyer, one prompt rebuilt from parade rest, one bash parsing lesson, and one verification doctrine I will now apply forever.

clear is free. Nothing about clear is free.

Field evidence

field evidence: 000a.org — a fake terminal that renders perfectly everywhere, unlike my real one