Subject: bug#78572: 30.1; Tramp Project error message loop - File is missing

From: Michael Albinus <[email-masked]>
Date: Tue, 27 May 2025 20:58:40 +0200

Alexis Bakatine <[email-masked]> writes:

> Hello Michael,

Hi Alexis,

> Now to reproduce the error:
>
> 1. I ran the exact same command you gave me below
>
> # emacs -Q -l project --eval '(setopt project-vc-extra-root-markers (quote (".project")))' --eval '(setopt project-mode-line t)' --eval '(setq tramp-verbose 10 tramp-debug-to-file t)' '/ssh:x|sudo::'
>
> 2. Connection happens successfully.
> 3. <RET> to open a random remote file (in this case it was .bash_history)
> 4. File open successfully.
> 5. Now, just do literally nothing, and wait for the Tramp session to
>    automatically timeout after a couple minutes.
>
> After the timeout, this is when the problems occur, with file missing
> error messages, and a debug backtrace buffer producing lots messages.

Thanks for the recipe. It is helpful.

>> When Emacs has finished (or crashed), there will be a file *debug tramp
>> sudo root <at> x* in either the ~/.cache/emacs/ /tmp/ directory. Pls send it.
>
> I cannot send the entire file because it grew up to 2.8M (38038 lines)
> only a few seconds after step 5. But here is the (I think) most relevant
> part and this is what gets printed in that file over and over:

What you've sent didn't help; the problem is indicated much earlier in
the debug file. This is why I always insist in sending the whole debug
information.

However, you gave an important hint in your recipe: wait, until the sudo
session times out. This wasn't said before (I believe). With this
information, I could reproduce the problem with both Emacs 30 and 31. It
even happens w/o multi-hop file names. Let's check the debug buffer:

--8<---------------cut here---------------start------------->8---
;; Emacs: 30.1.90 Tramp: 2.7.3.30.2 -*- mode: outline; coding: utf-8; -*-
;; Location: /home/albinus/src/emacs-30/lisp/net/tramp.elc Git: emacs-30/d0c90bc9bfe8fedbff7f282086dc38458b1e0f9e
13:04:06.892642 tramp-get-connection-property (7) # ~root undef; cache used: nil
--8<---------------cut here---------------end--------------->8---

This is where it starts.

--8<---------------cut here---------------start------------->8---
13:04:28.261984 tramp-send-command (6) # tramp_perl_file_name_all_completions /root/ 2>/dev/null; echo tramp_exit_status $?
13:04:28.300459 tramp-wait-for-regexp (6) #
(
("./" "/root/." t t t)
("../" "/root/.." t t t)
(".bashrc" "/root/.bashrc" nil t t)
(".cache/" "/root/.cache" t t t)
(".profile" "/root/.profile" nil t t)
(".ssh/" "/root/.ssh" t t t)
("snap/" "/root/snap" t t t)
(".vnc/" "/root/.vnc" t t t)
(".config/" "/root/.config" t t t)
(".viminfo" "/root/.viminfo" nil t t)
(".vim/" "/root/.vim" t t t)
(".local/" "/root/.local" t t t)
("tmp/" "/root/tmp" t t t)
)
tramp_exit_status 0
///701580ff750d89979a541cae0f26aa39#$
--8<---------------cut here---------------end--------------->8---

The last command before the session timeout. Emacs is still busy,
because the project-mode-line-format must be refreshed again and
again. But these information are taken from Tramp's cache; no activity
on the wire.

--8<---------------cut here---------------start------------->8---
13:09:13.361210 tramp-timeout-session (3) # Timeout session /sudo:root@ubuntu-2404:
--8<---------------cut here---------------end--------------->8---

sudo's session timeout after ca 5 minutes due to inactivity on the
wire. Usually, this is not problem. Next time a command is sent, the
connection is reestablished. But see the problem:

--8<---------------cut here---------------start------------->8---
13:09:13.371925 tramp-get-file-property (8) # /root file-directory-p undef; inhibit: 10; cache used: nil; cached at: nil
13:09:13.372124 tramp-get-file-property (8) # /root file-truename nil; inhibit: 10; cache used: nil; cached at: nil
13:09:13.372280 tramp-get-connection-property (7) # test undef; cache used: nil
13:09:13.372436 tramp-get-test-command (5) # Finding a suitable ‘test’ command
13:09:13.373726 tramp-get-connection-property (7) # null-device undef; cache used: nil
13:09:13.374313 tramp-set-connection-property (7) # null-device /dev/null
13:09:13.374687 tramp-file-name-handler (5) # Non-essential received in operation (file-directory-p /sudo:root@ubuntu-2404:/root)
13:09:13.668243 tramp-file-name-handler (10) #
  backtrace()
  tramp-file-name-handler(file-directory-p "/sudo:root@ubuntu-2404:/root")
  file-directory-p("/sudo:root@ubuntu-2404:/root/")
  locate-dominating-file("/sudo:root@ubuntu-2404:/root/" #f(compiled-function (d) #<bytecode -0x1cbf71e3d2025995>))
  project-try-vc--search("/sudo:root@ubuntu-2404:/root/")
  project-try-vc("/sudo:root@ubuntu-2404:/root/")
  run-hook-with-args-until-success(project-try-vc "/sudo:root@ubuntu-2404:/root/")
  project--find-in-directory("/sudo:root@ubuntu-2404:/root/")
  project-current()
  project-mode-line-format()
  eval((project-mode-line-format) t)
  redisplay_internal\ \(C\ function\)()
--8<---------------cut here---------------end--------------->8---

Tramp needs to know, whether "/sudo:root@ubuntu-2404:/root" is a
directory. It asks the cache (first line), but this doesn't have the
information (it returns undef). So Tramp must go on wire in order to
compute the information. But his fails as well ("Non-essential received
in operation..."), resulting in an error. Why this? Hmm, in
project-current, non-essential is bound to t, telling Tramp it should
*not* establish a new connection. This is an optimization I believe, see
bug#69584. And here we are.

While project-mode-line-format is called again and again, Tramp will
block. I've played yesterday and today with it; there's no simple
solution. For the time being, you could disable the session timeout for
your sudo target. Add something like this to your init file:

--8<---------------cut here---------------start------------->8---
(add-to-list 'tramp-connection-properties (list (regexp-quote "/sudo:root@x:") "session-timeout" nil))
--8<---------------cut here---------------end--------------->8---

Does this work for you?

I'll continue to find a solid solution, which doesn't require this
workaround.

Best regards, Michael.