How to fix the missing keymaps in Debian and Ubuntu (localectl: Failed to read list of keymaps)

Written by - 4 comments

Published on - Listed in Linux


While investigating a missing keyboard mapping error in Citrix Workspace app, one of the first ideas was to actually verify that the system keyboard mappings (keymaps) are installed on the system.

Although it turned out to be another cause in the Citrix Workspace app, the analysis let me stumble on another problem with the keymaps: The keymaps are not detected by the system!

keymaps, kbd and systemd

The whole configuration about keymaps has changed in recent years. The keymaps are part of the kbd project (Linux keyboard tools). The description of kbd is:

The kbd project contains utilities for managing Linux console (Linux console, virtual terminals, keyboard, etc.) – mainly, what they do is loading console fonts and keyboard maps.

However it's not kbd itself loading the keymaps. On a Debian-based system, this job is supposedly done by the console-data package, which holds the actual keymap files - acorrding to the package description:

This package provides the standard data files for the Linux console tools. This includes keyboard definitions (keymaps), console fonts for various encodings, maps defining the standard charsets for use by text applications, and fallback tables allowing to approximate an unavailable character's glyph with the glyph of another character in the current font. 

But that is still not enough. To view and configure keymaps, a command localectl is in charge. This command should then talk to a Systemd service, called systemd-localed. From localectl's man page:

localectl may be used to query and change the system locale and keyboard layout settings. It communicates with systemd-localed(8) to modify files such as /etc/locale.conf and /etc/vconsole.conf.

The ArchiWiki article on Keyboard configuration makes a pretty good summary how this all works together:

Keyboard mappings (keymaps), console fonts and console maps for the Linux console are provided by the kbd package (a dependency of systemd), which also provides many low-level tools for managing text console. In addition, systemd also provides the localectl tool, which can control both the system locale and keyboard layout settings for both the console and Xorg. 

So far to the theory. The reality on Debian-based systems, including Ubuntu and Linux Mint, is different.

Failed to read list of keymaps: No such file or directory

The first interesting hint is shown when simply launching localectl (which is installed through the systemd package). Without any parameters, the output should show the current languge settings (locale) and the keyboard configuration for both the graphical sessions (X11) and the console (VC, short for virtual console):

ck@mint ~ $ localectl
   System Locale: LANG=en_US.UTF-8
                  LC_NUMERIC=de_CH.UTF-8
                  LC_MONETARY=de_CH.UTF-8
                  LC_PAPER=de_CH.UTF-8
                  LC_NAME=de_CH.UTF-8
                  LC_ADDRESS=de_CH.UTF-8
                  LC_TELEPHONE=de_CH.UTF-8
                  LC_MEASUREMENT=de_CH.UTF-8
                  LC_IDENTIFICATION=de_CH.UTF-8
       VC Keymap: n/a
      X11 Layout: ch
       X11 Model: pc105
     X11 Variant: legacy

From the output we can see that VC Keymap is not set. Even though there is no negative impact on the console noticeable, it still looks "weird". Let's try to set a keymap for the console. To find the available keymaps we can first list them:

ck@mint ~ $ localectl list-keymaps
Failed to read list of keymaps: No such file or directory

Erm... what? Failed to read? No such file or directory? What exactly is missing here? To find out more, we can run strace in front of the localectl command to try and find the paths in question:

ck@mint ~ $ strace -f localectl list-keymaps
execve("/usr/bin/localectl", ["localectl", "list-keymaps"], 0x7ffd6b311870 /* 63 vars */) = 0
brk(NULL)                               = 0x557c2522f000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe3f53bf50) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f212aa64000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
[...]
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0AUTH EXTERNAL\r\nDATA\r\n", iov_len=22}, {iov_base="NEGOTIATE_UNIX_FD\r\n", iov_len=19}, {iov_base="BEGIN\r\n", iov_len=7}], msg_iovlen=3, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT|MSG_NOSIGNAL) = 48
gettid()                                = 15142
futex(0x7f212aa621d0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
gettid()                                = 15142
newfstatat(AT_FDCWD, "/usr/share/keymaps", 0x7ffe3f53be90, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/share/kbd/keymaps", 0x7ffe3f53be90, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/kbd/keymaps", 0x7ffe3f53be90, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/kbd/keymaps", 0x7ffe3f53be90, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)

openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
newfstatat(4, "", {st_mode=S_IFREG|0644, st_size=2996, ...}, AT_EMPTY_PATH) = 0
read(4, "# Locale name alias data base.\n#"..., 4096) = 2996
read(4, "", 4096)                       = 0
close(4)                                = 0
openat(AT_FDCWD, "/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
writev(2, [{iov_base="\33[0;1;31m", iov_len=9}, {iov_base="Failed to read list of keymaps: "..., iov_len=57}, {iov_base="\33[0m", iov_len=4}, {iov_base="\n", iov_len=1}], 4Failed to read list of keymaps: No such file or directory
) = 71
recvmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="DATA\r\nOK 3933d969e905dbff46be4e1"..., iov_len=256}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) = 58
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1\0\0\0\0\1\0\0\0m\0\0\0\1\1o\0\25\0\0\0/org/fre"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT|MSG_NOSIGNAL) = 128
recvmsg(3, {msg_namelen=0}, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable)
ppoll([{fd=3, events=POLLIN}], 1, {tv_sec=24, tv_nsec=999909000}, NULL, 8) = 1 ([{fd=3, revents=POLLIN}], left {tv_sec=24, tv_nsec=999598218})
recvmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\2\1\1\v\0\0\0\1\0\0\0=\0\0\0\6\1s\0\6\0\0\0", iov_len=24}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) = 24
recvmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base=":1.296\0\0\5\1u\0\1\0\0\0\10\1g\0\1s\0\0\7\1s\0\24\0\0\0"..., iov_len=67}], msg_iovlen=1, msg_controllen=0, msg_flags=MSG_CMSG_CLOEXEC}, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) = 67
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

In the strace output we can see that a couple of paths were checked for keymaps:

  • /usr/share/keymaps
  • /usr/share/kbd/keymaps
  • /usr/lib/kbd/keymaps
  • /lib/kbd/keymaps

All these paths returned "No such file or directory" as error. Finally, the localectl command exited with error code 1.

But the keymaps are installed?

By manually checking both installed kbd and console-data packages, we can see the actual keymap files were installed by the console-data package:

ck@mint ~ $ dpkg -L kbd | grep map
/usr/bin/loadunimap
/usr/bin/mapscrn
/usr/bin/mk_modmap
/usr/share/man/man5/keymaps.5.gz
/usr/share/man/man8/loadunimap.8.gz
/usr/share/man/man8/mapscrn.8.gz
/usr/share/man/man8/mk_modmap.8.gz

ck@mint ~ $ dpkg -L console-data | grep map
/usr/share/console/lists/console-data.keymap-list
/usr/share/console/lists/console-keymaps-acorn
/usr/share/console/lists/console-keymaps-amiga
/usr/share/console/lists/console-keymaps-at
/usr/share/console/lists/console-keymaps-atari
/usr/share/console/lists/console-keymaps-dec
/usr/share/console/lists/console-keymaps-mac
/usr/share/console/lists/console-keymaps-sun
/usr/share/console/lists/console-keymaps-usb
/usr/share/console/lists/keymaps
/usr/share/console/lists/keymaps/console-data.keymaps
/usr/share/doc/console-data/examples/hypermap.m4.gz
/usr/share/doc/console-data/keymaps
/usr/share/doc/console-data/keymaps/README
/usr/share/doc/console-data/keymaps/README.sparc
/usr/share/doc/console-data/keymaps/hypermap.m4.gz
/usr/share/doc/console-data/keymaps/no-latin1.doc
/usr/share/doc/console-data/keymaps/se.readme
/usr/share/keymaps
/usr/share/keymaps/amiga
/usr/share/keymaps/amiga/amiga-de.kmap.gz
/usr/share/keymaps/amiga/amiga-es.kmap.gz
/usr/share/keymaps/amiga/amiga-fr.kmap.gz
/usr/share/keymaps/amiga/amiga-it.kmap.gz
/usr/share/keymaps/amiga/amiga-se.kmap.gz
/usr/share/keymaps/amiga/amiga-sg.kmap.gz
/usr/share/keymaps/amiga/amiga-us.kmap.gz
/usr/share/keymaps/atari
/usr/share/keymaps/atari/atari-de-deadkeys.kmap.gz
/usr/share/keymaps/atari/atari-de-emacs.kmap.gz
/usr/share/keymaps/atari/atari-de.kmap.gz
/usr/share/keymaps/atari/atari-fr.kmap.gz
/usr/share/keymaps/atari/atari-se-deadkeys.kmap.gz
/usr/share/keymaps/atari/atari-se.kmap.gz
/usr/share/keymaps/atari/atari-uk-deadkeys.kmap.gz
/usr/share/keymaps/atari/atari-uk.kmap.gz
/usr/share/keymaps/atari/atari-us-deadkeys.kmap.gz
/usr/share/keymaps/atari/atari-us.kmap.gz
/usr/share/keymaps/i386
/usr/share/keymaps/i386/azerty
/usr/share/keymaps/i386/azerty/azerty.kmap.gz
/usr/share/keymaps/i386/azerty/be-latin1.kmap.gz
/usr/share/keymaps/i386/azerty/be2-latin1.kmap.gz
/usr/share/keymaps/i386/azerty/fr-latin0.kmap.gz
/usr/share/keymaps/i386/azerty/fr-latin1.kmap.gz
/usr/share/keymaps/i386/azerty/fr-latin9.kmap.gz
[...]

The path /usr/share/keymaps/ also matches the first path attempted by localectl before. Why would localectl still fail to read the keymaps?

It's a known Debian bug

A couple of minutes of research revealed an existing Debian Bug #790955, which was reported a long time ago (in July 2015). The reporter noticed the same findings as I did with no keymaps showing up using localectl.

Reading throught the bug report and comments shows that console-data - the package holding the keymaps, as we found out before - is actually deprecated in favour of kbd and console-setup. Other comments indicate that the Debian-way of installing and configuring the keymaps is a home-grown solution and differs from the other Linux distributions with Systemd:

The main issue afaics is that Fedora uses the keymap files from kbd. We do have a kbd package in debian, but it only provides binaries but not the keymap data files. The keymap files that are installed on a Debian system seem to come from console-data. console-data seems to be based off ftp://lct.sourceforge.net/pub/lct/ but is nowadays more or less a Debian-only solution. One obvious difference between the  keymap files shipped by kbd and console-data is, that kbd uses a map.gz file extension whereas console-data uses kmap.gz.

The console-data package maintainer, Alastair McKinstry, commented and confirmed in November 2018:

I still in principle maintain console-data and console-common, mostly fixing egregious bugs, but they are deprecated in favour of kbd / console-setup. [...] Ideally, console-data and console-common would be obsoleted and removed from Debian.

To this day, the bug is open and therefore not resolved.

Use keymaps from kbd upstream project

Although the keymaps are actually installed by the console-data package, they are not readable by localectl and therefore can't be used to set the virtual console keymap. So let's switch focus to the solution. Instead of using the locally installed keymaps, we can download the keymaps from the upstream project (kbd). 

Download the current version (2.5.1) as a compressed tarball and unpack it:

ck@mint ~ $ wget https://mirrors.edge.kernel.org/pub/linux/utils/kbd/kbd-2.5.1.tar.gz -O /tmp/kbd-2.5.1.tar.gz
ck@mint ~ $ cd /tmp/ && tar xzf kbd-2.5.1.tar.gz

The keymaps from kbd can be found inside the unpacked kbd directory inside data/keymaps. Simply copy the whole content into the /usr/share/keymaps/ path:

ck@mint ~ $ sudo cp -Rp /tmp/kbd-2.5.1/data/keymaps/* /usr/share/keymaps/

Now run localectl again to list the available keymaps. And hey, they finally show up now:

ck@mint ~ $ localectl list-keymaps
3l
ANSI-dvorak
adnw
amiga-de
amiga-us
apple-a1048-sv
apple-a1243-sv
apple-a1243-sv-fn-reverse
apple-internal-0x0253-sv
apple-internal-0x0253-sv-fn-reverse
[...]

I can even find the Swiss keymaps:

ck@mint ~ $ localectl list-keymaps | grep -i CH
de_CH-latin1
fr_CH
fr_CH-latin1
mac-de_CH
mac-fr_CH-latin1

Now that localectl detects the manually installed keymaps, we can set the keymap on the virtual console:

ck@mint ~ $ localectl set-keymap de_CH-latin1
ck@mint ~ $ localectl status
   System Locale: LANG=en_US.UTF-8
                  LC_NUMERIC=de_CH.UTF-8
                  LC_MONETARY=de_CH.UTF-8
                  LC_PAPER=de_CH.UTF-8
                  LC_NAME=de_CH.UTF-8
                  LC_ADDRESS=de_CH.UTF-8
                  LC_TELEPHONE=de_CH.UTF-8
                  LC_MEASUREMENT=de_CH.UTF-8
                  LC_IDENTIFICATION=de_CH.UTF-8
       VC Keymap: de_CH-latin1
      X11 Layout: ch
       X11 Model: pc105
     X11 Variant: legacy

The VC Keymap now finally shows "de_CH-latin1" and not "n/a" anymore.


Add a comment

Show form to leave a comment

Comments (newest first)

Jan from Czechia wrote on Nov 8th, 2023:

Still valid in Debian 12 (Bookworm), thanks for the working solution :)


Sol from wrote on Oct 14th, 2023:

Thank you, this fixed the problem for me.
I’ve had to also run `setupcon -k` at the end, to live-reload the updated keymap.


Cyber Bob from Cyberland wrote on Oct 10th, 2023:

Wow. This was informative. I was running around in circles trying to figure that one out. You saved me hours. Cheers!


Eberhard from DE/Bavaria wrote on Apr 17th, 2023:

Thank you that fixed my problem, too
elanger@nbwwks284:~$ localectl status
System Locale: LANG=de_DE.UTF-8
VC Keymap: de
X11 Layout: de
X11 Model: pc105
X11 Options: terminate:ctrl_alt_bksp


RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Icingaweb   Icingaweb2   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder   


Update cookies preferences