Skip to content

khoj.el kills the Emacs server (and other buffer-less processes) when the khoj server is unreachable #1378

Description

@dustinfarris

Describe the bug

When the khoj server is unreachable, khoj.el's failed-request handler kills unrelated Emacs processes — including the emacsclient server listener, whose socket file is then removed by server-sentinel. The practical symptom: ~60 seconds after starting Emacs (when the auto-index timer first fires), emacsclient stops working with can't find socket; have you started the server?, and every hourly re-index kills any manually restarted server again. Buffer-less processes other than the server listener (e.g. live emacsclient connections) are killed too.

Root cause

khoj--delete-open-network-connections-to-server (khoj.el:1118, v2.0.0-beta.28) iterates the whole process-list and matches each process by the name of its buffer:

(defun khoj--delete-open-network-connections-to-server ()
  "Delete all network connections to khoj server."
  (dolist (proc (process-list))
    (let ((proc-buf (buffer-name (process-buffer proc)))
          (khoj-network-proc-buf (string-join (split-string khoj-server-url "://") " ")))
      (when (string-match (format "%s" khoj-network-proc-buf) proc-buf)
        (ignore-errors (delete-process proc))))))

Two problems combine:

  1. Many processes have no buffer (process-buffernil), and (buffer-name nil) returns the name of the current buffer — it does not error.
  2. This function is called from the url-retrieve failure callback in khoj--send-index-update-request (khoj.el:447), where the current buffer is the failed url-http buffer, e.g. *http localhost:42110* — which matches the "http localhost:42110" pattern.

So every buffer-less process in the session matches and gets delete-processd. That includes the server-start listener process; deleting it flips its status to closed, and server-sentinel then deletes the server socket file.

The deletions also cascade: deleting one pending url-http process fires its sentinel, which invokes the failure callback and khoj--delete-open-network-connections-to-server again, recursively.

To Reproduce

  1. Configure khoj.el with khoj-auto-index enabled (the default) and a khoj-server-url pointing at a server that is not running.
  2. Start Emacs with server-start (or a daemon), verify emacsclient --eval t works.
  3. Wait for the first auto-index run (60s), or trigger M-x khoj--server-index-files manually.
  4. emacsclient now fails with can't find socket; lsof -U -a -p <emacs-pid> shows the listening socket fd is gone, and the socket file has been removed.

Backtrace captured with advice on delete-process at the moment the listener dies:

delete-process(#<process server>)          ; ← the Emacs server listener
khoj--delete-open-network-connections-to-server()
#f(compiled-function (status) ...)((:error (error connection-failed "deleted\n" :host "localhost" :service 42110)))
url-http-activate-callback()
url-http-async-sentinel(#<process localhost> "deleted\n")

Suggested fix

Only consider processes that actually own a live buffer:

(defun khoj--delete-open-network-connections-to-server ()
  "Delete all network connections to khoj server."
  (let ((khoj-network-proc-buf (string-join (split-string khoj-server-url "://") " ")))
    (dolist (proc (process-list))
      (let ((buf (process-buffer proc)))
        (when (and buf
                   (buffer-live-p buf)
                   (string-match-p khoj-network-proc-buf (buffer-name buf)))
          (ignore-errors (delete-process proc)))))))

Optionally, khoj--server-index-files could also skip the index run entirely (with a message) when a quick /api/health check fails, instead of building and sending the full multipart body only to fail per batch.

Platform

  • Server: Docker (server not running is the trigger)
  • Client: Emacs 30.2, khoj.el 2.0.0-beta.28 (macOS)

If applicable, share the file type you were trying to index

org-mode (irrelevant to the bug — any failed index request triggers it)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions