How to Fix Broken or Missing Characters in Terminal on Fedora

Fix broken terminal characters on Fedora by setting the LANG and LC_ALL environment variables to en_US.UTF-8.

Broken characters in the terminal

You open your terminal to run a quick command and the output looks like garbage. Your prompt shows é instead of Γ©, file names contain random symbols, and ls returns a wall of question marks. You just installed a new font or switched from a live USB, and now the text rendering is broken. This happens when the terminal emulator, the shell, and the system locale disagree on how to interpret bytes.

What is actually happening

Computers store text as numbers. The mapping between those numbers and the glyphs you see is the encoding. UTF-8 is the standard on Fedora. If the terminal thinks the stream is Latin-1 but the data is UTF-8, multi-byte sequences get split and rendered as wrong characters. This is a handshake failure. The application sends bytes. The terminal receives bytes. They must agree on the language.

Think of the locale as a translator. The application speaks in bytes. The terminal needs a translator to turn bytes into glyphs. If the translator is missing or speaks the wrong dialect, you get gibberish. If LANG is set to C or POSIX, the terminal falls back to ASCII-only interpretation. Any byte above 127 becomes a mystery. The terminal displays replacement characters or splits multi-byte sequences into individual bytes, which renders as mojibake like é.

Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. The locale configuration lives in /etc/locale.conf. Using the proper tool updates this file safely without touching package-owned directories.

Fix the locale settings

Check the active environment variables first. The mismatch usually originates in LANG or LC_ALL.

Here is how to inspect the current locale settings and identify which variable is causing the conflict.

locale # Prints the active locale environment variables.
# Look for LANG and LC_ALL. If either is set to 'C' or 'POSIX',
# the terminal will refuse to render multi-byte characters.

If LANG is missing or incorrect, set it for the current session. This restores rendering immediately.

Here is the immediate fix to restore character rendering in your current session.

export LANG=en_US.UTF-8 # Sets the default locale for the shell session.
export LC_ALL=en_US.UTF-8 # Forces all locale categories to match LANG.
# LC_ALL overrides LANG. Setting both ensures no category falls back to 'C'.

Make the change permanent so it survives reboots and new login sessions. Use localectl to update the system configuration.

Here is how to make the change permanent across reboots and new login sessions.

localectl set-locale LANG=en_US.UTF-8 # Writes the setting to /etc/locale.conf.
# This command updates the system configuration without manual file edits.
# It also triggers systemd to notify running services of the change.

Use localectl. Manual edits to /etc/locale.conf drift, localectl stays consistent.

Verify the fix

Confirm the environment variables are correct and the terminal renders glyphs properly.

Here is how to verify the environment variables are correct and the terminal renders glyphs properly.

locale | grep LANG # Filters output to show the active LANG variable.
echo "CafΓ© rΓ©sumΓ© naΓ―ve" # Prints accented characters to test rendering.
# If the output shows correct glyphs, the fix is successful.

Restart the shell before you blame the font. Half the time the variable is just stale.

Common pitfalls and error patterns

The LC_ALL variable overrides everything. If LC_ALL is set to C in your ~/.bashrc or a legacy script, your LANG=en_US.UTF-8 is ignored. This is the most common trap.

Here is how to check for overriding variables that might mask your intended locale.

env | grep LC_ # Lists all LC variables in the environment.
# If LC_ALL is set, it takes precedence over LANG.
# If LC_CTYPE is set to 'C', character rendering breaks even if LANG is UTF-8.

Check LC_ALL before you reinstall packages. An override in your dotfile is the usual culprit.

Sometimes the system reports the locale is missing. You will see this error when running locale or starting a new session.

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory

This error means the locale package is not installed or the locale has not been generated. Fedora splits locales into language pack packages. Minimal installs or containers might lack them.

Here is how to install the missing language pack and generate the locale.

dnf install glibc-langpack-en # Installs the English language pack.
# Fedora splits locales into packages. The base system might lack specific packs.
# Run dnf upgrade --refresh weekly. It ensures metadata is fresh before you install langpacks.

Remote sessions often lose locale settings. The SSH client sends LANG and LC_* variables. The server must accept them. If your remote terminal shows C locale, check the server configuration.

Here is how to verify the SSH server configuration allows the client to send locale variables.

# Excerpt from /etc/ssh/sshd_config
AcceptEnv LANG LC_* # Tells sshd to accept locale variables from the client.
# If this line is commented out, remote sessions default to 'C'.

If SSH fails to send locale, check journalctl -xeu sshd. The journalctl -xe command reads better than journalctl alone. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style.

If the locale is correct but you see boxes, the font is missing glyphs. This is a font issue, not a locale issue. Fedora uses google-noto-sans-fonts and google-noto-sans-cjk-fonts for broad coverage.

Here is how to install comprehensive font sets to cover missing glyphs.

dnf install google-noto-sans-fonts google-noto-sans-cjk-fonts # Installs comprehensive font sets.
# Missing fonts cause 'tofu' boxes even when the encoding is correct.
# Restart the terminal emulator after installing fonts to reload the font cache.

Place session exports in ~/.bashrc for interactive shells. Place system-wide exports in /etc/profile.d/. Do not put them in ~/.bash_profile unless you know the difference. ~/.bashrc runs for every interactive shell. ~/.bash_profile runs only for login shells. Terminal emulators usually start non-login interactive shells.

When to use which approach

Use export LANG=... when you need a quick fix for the current terminal session. Use localectl set-locale when you want the setting to persist across reboots and services. Use dnf install glibc-langpack-* when the system reports the locale is missing or not generated. Use the terminal emulator's preferences when the system locale is correct but the font lacks glyphs. Use AcceptEnv in sshd_config when remote sessions default to the C locale. Stay on en_US.UTF-8 if you are unsure. It is the safest default for English-speaking users.

Where to go next