known·good

Notes / cupsprintersmdnsavahinss-mdnsarch

CUPS "Unable to locate printer *.local" even though avahi-resolve finds the printer

· by shaun, written up with Claude

CUPS jobs to an ipp://printer.local queue never printed and lpstat showed "Unable to locate printer". Avahi could see the printer, but /etc/nsswitch.conf had no mdns entry, so normal name lookups for .local failed. Adding mdns4_minimal [NOTFOUND=return] to the hosts line fixed it.

Tested onArch Linux; CUPS with an ipp:// queue addressed by the printer's mDNS (.local) name; avahi-daemon; nss-mdns installed

Symptoms #

A network printer had been set up in CUPS using its mDNS hostname. The queue accepted jobs, but nothing printed and jobs piled up. lpstat -t showed:

textdevice for Office_Printer: ipp://printer.local:631/ipp/print
Unable to locate printer "printer.local".

At the same time, Avahi had no trouble finding the printer:

bashavahi-resolve -n printer.local     # returns the printer's address

But ordinary name resolution did not:

bashgetent hosts printer.local         # prints nothing
ping printer.local                 # Name or service not known

Root cause #

CUPS resolves the queue's hostname through the normal glibc resolver (NSS), not by asking Avahi directly. Whether NSS knows about .local names is decided by the hosts: line in /etc/nsswitch.conf, which here was:

texthosts: files dns myhostname

There is no mdns module in that list, so .local lookups went to files and dns, both of which fail. The nss-mdns package (which provides the mdns* NSS modules) was already installed; it just was not enabled in nsswitch.conf. On Arch it is only an optional dependency of avahi, so on another machine you may need pacman -S nss-mdns first.

The difference between avahi-resolve (works) and getent hosts (fails) is the tell: avahi-resolve talks to avahi-daemon directly, getent goes through NSS the way CUPS does.

Fix #

Add mdns4_minimal [NOTFOUND=return] to the hosts: line, before dns:

bashsudo sed -i.bak 's|^hosts:.*|hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname|' /etc/nsswitch.conf

If your hosts: line has other entries (for example resolve or mymachines), edit it by hand instead of replacing the whole line; the point is to insert mdns4_minimal [NOTFOUND=return] before dns.

Check:

bashgetent hosts printer.local         # now prints the printer's address

No service restart is needed: NSS reads nsswitch.conf on each lookup, and CUPS picked up the change on the next job.

[NOTFOUND=return] stops the lookup when mDNS says a .local name does not exist, instead of falling through to DNS. That avoids slow upstream DNS queries for names that will never resolve there.

The same fix applies to any .local device on the machine (AirPlay receivers, other Bonjour/mDNS hosts), not only printers.

Do not cancel the stuck jobs #

Jobs stuck on a name-resolution failure are real prints. Once the hostname resolves, CUPS retries them and they print. If you cancel them while diagnosing (cancel -a), they have to be printed again. We made this mistake once; leave the queue alone and let it flush.

How it was found #

bashlpstat -t                          # queues and the last error per queue
avahi-resolve -n printer.local     # what Avahi sees
getent hosts printer.local         # what NSS (and CUPS) sees: the gap
avahi-browse -art                  # list mDNS services on the network
grep ^hosts /etc/nsswitch.conf     # look for mdns4_minimal
pacman -Q nss-mdns                 # confirm the NSS module is installed

References #