Corrigindo Avisos "cannot set LC_ALL" de Locale

Corrigindo Avisos "cannot set LC_ALL" de Locale

O Que Você Vai Aprender

  • Por que o aviso cannot set LC_ALL / setlocale aparece
  • Como identificar a variável ofensora com locale / locale -a
  • Como silenciar rapidamente e como gerar o locale para uma correção permanente

Conclusão (padrão de triagem)

  • O aviso significa uma coisa: o locale solicitado não existe no sistema
  • Primeiro verifique o aviso com locale, depois os locales que você realmente tem com locale -a
  • Se estiver ausente, gere com locale-gen; se tiver pressa, silencie com export LC_ALL=C

Premissas (ambiente alvo)

  • SO: Ubuntu / Debian / família RHEL (glibc com systemd)
  • Pode acontecer em terminal local, servidor SSH alvo ou container

Por que o aviso "cannot set LC_ALL" aparece?

Conclusão: Porque o locale que suas variáveis LANG / LC_* solicitam (ex: en_US.UTF-8) não está gerado ou instalado naquele sistema. Ao solicitar um locale que não existe, a glibc faz fallback para o locale C.

Um locale agrupa idioma, codificação de caracteres e formatação de data/número sob um nome como en_US.UTF-8 ou ja_JP.UTF-8. Na inicialização, um programa chama setlocale() e resolve o locale solicitado na ordem de prioridade: LC_ALLLC_*LANG.

Quando o nome solicitado não existe no sistema, a glibc emite um aviso e faz fallback para o locale seguro C (POSIX). Mensagens típicas:

# o proprio comando locale
locale: Cannot set LC_ALL to default locale: No such file or directory

# bash / varios comandos
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory

# perl (comum em apt e hooks do Git)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LC_ALL = (unset),
	LC_CTYPE = "UTF-8",
	LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

Principais padrões de "não existe"

  • O pacote locales em si não está instalado (containers mínimos, imagens cloud)
  • O pacote está presente mas o locale nunca foi gerado (locale-gen não executado)
  • O SSH encaminhou o locale do seu terminal e o servidor alvo não tem o mesmo
  • Um erro de digitação (ex: omitir o codeset como em en_US em vez de en_US.UTF-8, ou separador errado como en-US.UTF-8) aponta para um nome que não existe

Como encontro qual variável está errada?

Conclusão: Use locale para os valores atuais e a variável ofensora, e locale -a para a lista de locales disponíveis. Se o nome solicitado não está na lista, essa é a causa.

Executar locale mostra as configurações atuais e qual variável é o problema de uma vez.

$ locale
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
...
LC_ALL=

Em seguida, liste os locales que o sistema pode realmente usar.

$ locale -a
C
C.UTF-8
POSIX

Aqui en_US.UTF-8 é solicitado, mas a lista tem apenas locales da família C. O nome solicitado não aparecer em locale -a é a evidência decisiva.

Atenção para variações de nome. locale -a pode imprimir na forma en_US.utf8 (minúsculo, sem hífen), mas uma configuração LANG=en_US.UTF-8 é tratada como a mesma. Entretanto, en_US (sem codificação) e en_US.UTF-8 são diferentes, então verifique se o sufixo também corresponde.

Por que o aviso aparece via SSH?

Conclusão: O cliente SSH encaminha seu locale local com SendEnv LANG LC_*, e o servidor aceita via AcceptEnv. Se o servidor não tem aquele locale, você recebe o aviso em cada login.

Se nunca aparece localmente mas aparece toda vez que você se conecta via SSH a um servidor, esta é quase sempre a causa. A maioria das distros vem com uma configuração de cliente SSH com esta linha:

# /etc/ssh/ssh_config ou ~/.ssh/config
SendEnv LANG LC_*

Isso envia seu LANG=en_US.UTF-8 (e similares) para o servidor. O AcceptEnv LANG LC_* do /etc/ssh/sshd_config do servidor os recebe e configura o ambiente da sessão. Se o servidor não tem aquele locale, setlocale falha quando o shell inicia.

Você tem duas opções: instalar o locale no servidor (passos abaixo) ou parar de encaminhá-lo. Para parar o encaminhamento, edite a configuração do cliente.

# Desabilitar encaminhamento para um host em ~/.ssh/config
Host myserver
    SendEnv -LANG -LC_*

Para evitar o aviso de locale em uma única conexão, envie o locale C que está sempre presente para sobrescrevê-lo. LC_ALL tem precedência sobre todos os outros LC_* e LANG, então ele vence mesmo quando um valor foi encaminhado.

$ LC_ALL=C ssh user@myserver

Como gerar ou instalar o locale? (Debian / Ubuntu)

Conclusão: Instale o pacote locales, gere o locale alvo com locale-gen e defina o padrão com update-locale. O interativo dpkg-reconfigure locales faz o mesmo.

No Debian / Ubuntu, um locale requer dois passos: instalar o pacote e gerá-lo.

# 1. O pacote locales (para sistemas minimos sem ele)
$ sudo apt update && sudo apt install -y locales

# 2. Gerar os locales alvo
$ sudo locale-gen en_US.UTF-8 ja_JP.UTF-8

# 3. Definir o locale padrao do sistema
$ sudo update-locale LANG=en_US.UTF-8

Verifique novamente com locale -a que foi gerado. A configuração persistente fica em /etc/default/locale.

$ cat /etc/default/locale
LANG=en_US.UTF-8

Para escolher de um menu, use o comando abaixo e selecione locales com a barra de espaço para gerá-los.

$ sudo dpkg-reconfigure locales

Mudanças de update-locale e /etc/default/locale só entram em vigor a partir de uma nova sessão de login. Para aplicá-las ao shell atual imediatamente, faça logout e login novamente, ou defina um valor por enquanto com export LANG=en_US.UTF-8.

Corrigindo no RHEL / Fedora

Conclusão: No RHEL 8 e posterior, instale o locale via pacote glibc-langpack-<lang> e defina o padrão com localectl set-locale.

No RHEL / CentOS Stream / Fedora, você instala um langpack por idioma.

# O conjunto de locale ingles
$ sudo dnf install -y glibc-langpack-en

# Adicione japones se precisar
$ sudo dnf install -y glibc-langpack-ja

# Definir o padrao do sistema
$ sudo localectl set-locale LANG=en_US.UTF-8

localectl é o comando comum de gerenciamento de locale em sistemas systemd, e ele escreve a configuração em /etc/locale.conf. Verifique o valor atual com localectl status.

$ localectl status
   System Locale: LANG=en_US.UTF-8
       VC Keymap: us
      X11 Layout: us

Em um sistema da família Debian que também tem localectl (systemd), você pode definir o padrão com localectl set-locale também. Mas gerar o locale continua sendo trabalho do locale-gen, então a ordem gerar → localectl permanece a mesma.

Um workaround rápido quando você só quer silenciar

Conclusão: Use export LC_ALL=C ou export LANG=C.UTF-8 para mudar para um locale que certamente existe. Não é uma correção real, mas para o aviso instantaneamente.

Para uma execução de script ou tarefa pontual onde você "só quer que o aviso pare agora", aponte para um locale da família C que certamente existe.

# Silenciar completamente (mensagens em ingles, collation ASCII)
$ export LC_ALL=C

# Manter UTF-8 (disponivel na maioria dos sistemas)
$ export LANG=C.UTF-8
$ unset LC_ALL

C (= POSIX) e C.UTF-8 são embutidos na glibc e funcionam em quase todo lugar sem locale-gen. Escolher C.UTF-8 mantém sequências de bytes UTF-8 intactas enquanto usa mensagens em inglês.

LC_ALL é a variável de maior prioridade que sobrescreve todo LC_*. Fixá-la em C força a classificação de caracteres e ordem de ordenação para o locale C também. Colocar LC_ALL=C em um arquivo permanente (como .bashrc) convida outros bugs, então mantenha como workaround e corrija permanentemente gerando o locale.

Se você só quer silenciar um único script, delimite no topo.

#!/usr/bin/env bash
export LC_ALL=C.UTF-8

Checklist para prevenir recorrência

Conclusão: Pré-gere os locales que um servidor precisa, pare forwarding SSH desnecessário e evite fixar LC_ALL permanentemente, e avisos de locale são amplamente preveníveis.

Medida Comando / configuração Efeito
Gerar locales necessários sudo locale-gen en_US.UTF-8 Remove o nome solicitado ausente
Definir padrão explícito do sistema update-locale / localectl set-locale Fixa o padrão por login
Parar forwarding SSH desnecessário SendEnv -LANG -LC_* Previne importação de locales ausentes
Manter workarounds locais export LC_ALL=C.UTF-8 dentro de script Evita efeitos colaterais de fixação global

Copie e cole: diagnóstico de locale em uma linha

# Compare o locale solicitado contra o que esta disponivel
echo "--- solicitado ---"; locale 2>&1 | grep -E '^(LANG|LC_ALL|LC_CTYPE)='; \
  echo "--- disponivel ---"; locale -a

Próximas Leituras