company-lsp icon indicating copy to clipboard operation
company-lsp copied to clipboard

Error when auto-completion fires: wrong-type-argument arrayp nil

Open shackra opened this issue 6 years ago • 11 comments

I experienced the bug reported on #17

This has happen on Go and Python, and I expect to happen on other languages too.

After inserting the dot to fire auto completion with Company, it fails: nothing happens.

toggling debugging on error on reveals the following (python-mode running on the *scratch* buffer):

Debugger entered--Lisp error: (wrong-type-argument arrayp nil)
  company-lsp(prefix)
  apply(company-lsp prefix)
  company--force-sync(company-lsp (prefix) company-lsp)
  company--multi-backend-adapter((company-lsp :with company-yasnippet) prefix)
  company--begin-new()
  company--perform()
  company-auto-begin()
  company-idle-begin(#<buffer *scratch*> #<window 3 on *scratch*> 29 55)
  apply(company-idle-begin (#<buffer *scratch*> #<window 3 on *scratch*> 29 55))
  timer-event-handler([t 23239 7758 98423 nil company-idle-begin (#<buffer *scratch*> #<window 3 on *scratch*> 29 55) nil 197000])

This is my current configuration:

(use-package lsp-mode
  :init
  (add-hook 'prog-mode-hook 'lsp-mode))

(use-package lsp-ui
  :init (add-hook 'lsp-mode-hook 'lsp-ui-mode)
  :config
  (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
  (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references))

(use-package company
  :diminish company-mode
  :init
  (setf company-backends '((company-files
                            company-keywords
                            company-capf
                            company-yasnippet)
                           (company-abbrev company-dabbrev)))
  (setf company-idle-delay 0.5)
  (setf company-tooltip-limit 10)
  (setf company-minimum-prefix-length 1)
  (setf company-echo-delay 0)
  (setf company-auto-complete nil)
  (add-hook 'after-init-hook #'global-company-mode))

(use-package company-lsp
  :init
  (push 'company-lsp company-backends)
  (setf company-lsp-async t))

(use-package company-statistics
  :after (company)
  :init
  (setf company-statistics-file "~/.company-statistics-cache.el")
  (add-hook 'after-init-hook 'company-statistics-mode))

(use-package company-quickhelp
  :after (company)
  :config (company-quickhelp-mode 1))

(use-package lsp-python
  :after (lsp-mode)
  :init (add-hook 'python-mode-hook #'lsp-python-enable))

(use-package lsp-go
  :after go-mode
  :init
  (add-hook 'go-mode-hook #'lsp-go-enable)
  (setf lsp-go-go-command '("go-langserver" "-mode=stdio" "-gocodecompletion")))

;; http://emacs.stackexchange.com/questions/10431/get-company-to-show-suggestions-for-yasnippet-names
;; Add yasnippet support for all company backends
;; https://github.com/syl20bnr/spacemacs/pull/179

(defun company-mode/backend-with-yas (backend)
  (if (or (and (listp backend) (member 'company-yasnippet backend)))
      backend
    (append (if (consp backend) backend (list backend))
            '(:with company-yasnippet))))

(add-hook 'after-init-hook (lambda () (setf company-backends (mapcar #'company-mode/backend-with-yas company-backends))) t)

shackra avatar Apr 06 '18 07:04 shackra

@xianghx I fixed that with (setf lsp-go-go-command '("go-langserver" "-mode=stdio" "-gocodecompletion") but I don't know if it is related to my bug

shackra avatar Apr 06 '18 07:04 shackra

That is covered by use-package or I don't know what you are referring to.

shackra avatar Apr 06 '18 08:04 shackra

Which is the problem I'm reporting :)

shackra avatar Apr 06 '18 08:04 shackra

Sorry for late response.

For lsp-go: The go language server doesn't provide completion support. You can confirm it by M-x lsp-capabilities.

For lsp-python: It's unclear what went wrong. It's likely a bug in the code. I tried on my machine and it works well. Can you provide the following information for further debugging?

  1. Before opening any python file, M-x set-variable RET lsp-print-io RET t
  2. Open the problematic Python file, try completion
  3. Paste the content of the *Messages* buffer here
  4. Run M-x copmany-diag in the Python file with cursor after a dot, and paste the content of company-diag output here.

tigersoldier avatar Apr 09 '18 06:04 tigersoldier

Sorry I missed comment about emacs-lsp/lsp-go#6

With that patched I was able to trigger completion for Go.

I managed to trigger the error wrong-type-argument arrayp nil once. The lsp client was corrupted and lsp--cur-workspace local variable was somehow set to nil.

Are you constantly triggering this issue? There may be a bug on the lsp-mode side or go/python language server side. company-lsp can provide better messaging but cannot help with the root cause.

tigersoldier avatar Apr 09 '18 06:04 tigersoldier

Well, I think this is something related to lsp-mode because I was able to reproduce the exact same error in php-mode and js2-mode (both switched on *scratch* buffer).

Vue-lsp works fine, the auto-completion suggestion seems not related to what you write (It may be a thing of the server) and other features of lsp works too:

captura de pantalla de 2018-04-09 01-19-36 captura de pantalla de 2018-04-09 01-18-09

When I open a Javascript file, the auto-completion works fine in js2-mode:

captura de pantalla de 2018-04-09 01-23-00

The error still happens for python-mode in a project that had no setup.py, I added the file and try again but the error stills kicks in. Then I tried with a project that I built as a Python package (with a formal setup.py and everything and stills the issue happens).

Isn't there a way to spy the communications between lsp-mode and the servers? that would help a lot for bug reporting.

shackra avatar Apr 09 '18 07:04 shackra

Note this: Another unrelated package called importmagic experiences the exact same error:

Debugger entered--Lisp error: (wrong-type-argument arrayp nil)
  epc:call-deferred(nil get_unresolved_symbols "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\n\nimport tqdm\n\nPRICE = float(os.getenv(\"SPOYDERMAN_PRICE\", 0.012))\n\n\ndef listDB(client):\n    \"\"\" Lista todas las bases de datos relacionadas a proyecto spoyderman\n    \"\"\"\n    dbs = client.database_names()\n    for db in dbs:\n        if \"spoyderman_\" in db:\n            print(db.replace(\"spoyderman_\", \"📕 \"))\n\n\ndef countDB(client, db, beg, end):\n    \"\"\"Cuenta los documentos en la base de datos\n\n    db: nombre de la base de datos de interes\n    beg: inicio de la colección\n    end: cuanto recoger, -1 equivale a todo lo que hay en la base de datos\n\n    Por motivos de conveniencia retorna una cadena formateada con el precio de\n    la acotación de records, la cantidad de records y la misma colección\n\n    \"\"\"\n    tdb = client[\"spoyderman_\" + db]\n\n    if beg < 0:\n        beg = 0\n\n    if end <= 0:\n        collections = tdb.records.find()[beg:]\n    else:\n        collections = tdb.records.find()[beg:end]\n\n    count = collections.count()\n    return (\"\\n💸 USD$ {:.3f} ({} records)\".format(count * PRICE, count),\n            count, collections)\n\n\ndef exportDB(client, db, exporter, beg=0, end=0):\n    \"\"\" Exporta los documentos a un formato especificado por `exporter`\n\n    db: nombre de la base de datos de interes\n    exporter: una clase que se encarga del formateo\n    beg: inicio de la colección\n    end: cuanto recoger, `all` equivale a todo lo que hay en la base de datos\n    \"\"\"\n    money, count, collections = countDB(client, db, beg, end)\n\n    # Nombra el archivo al cual se hará la exportación de records\n    exporter.filename(db + \"_{}records_.\".format(count) +\n                      exporter.extension().lower())\n\n    for collection in tqdm.tqdm(\n            collections,\n            total=count,\n            desc=\"to {}\".format(exporter.extension())):\n        exporter.insert(collection)\n\n    exporter.close()\n    print(money)\n")
  epc:call-sync(nil get_unresolved_symbols "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport os\n\nimport tqdm\n\nPRICE = float(os.getenv(\"SPOYDERMAN_PRICE\", 0.012))\n\n\ndef listDB(client):\n    \"\"\" Lista todas las bases de datos relacionadas a proyecto spoyderman\n    \"\"\"\n    dbs = client.database_names()\n    for db in dbs:\n        if \"spoyderman_\" in db:\n            print(db.replace(\"spoyderman_\", \"📕 \"))\n\n\ndef countDB(client, db, beg, end):\n    \"\"\"Cuenta los documentos en la base de datos\n\n    db: nombre de la base de datos de interes\n    beg: inicio de la colección\n    end: cuanto recoger, -1 equivale a todo lo que hay en la base de datos\n\n    Por motivos de conveniencia retorna una cadena formateada con el precio de\n    la acotación de records, la cantidad de records y la misma colección\n\n    \"\"\"\n    tdb = client[\"spoyderman_\" + db]\n\n    if beg < 0:\n        beg = 0\n\n    if end <= 0:\n        collections = tdb.records.find()[beg:]\n    else:\n        collections = tdb.records.find()[beg:end]\n\n    count = collections.count()\n    return (\"\\n💸 USD$ {:.3f} ({} records)\".format(count * PRICE, count),\n            count, collections)\n\n\ndef exportDB(client, db, exporter, beg=0, end=0):\n    \"\"\" Exporta los documentos a un formato especificado por `exporter`\n\n    db: nombre de la base de datos de interes\n    exporter: una clase que se encarga del formateo\n    beg: inicio de la colección\n    end: cuanto recoger, `all` equivale a todo lo que hay en la base de datos\n    \"\"\"\n    money, count, collections = countDB(client, db, beg, end)\n\n    # Nombra el archivo al cual se hará la exportación de records\n    exporter.filename(db + \"_{}records_.\".format(count) +\n                      exporter.extension().lower())\n\n    for collection in tqdm.tqdm(\n            collections,\n            total=count,\n            desc=\"to {}\".format(exporter.extension())):\n        exporter.insert(collection)\n\n    exporter.close()\n    print(money)\n")
  importmagic--get-unresolved-symbols()
  importmagic-fix-imports()
  (progn (importmagic-fix-imports))
  (if (eq major-mode (quote python-mode)) (progn (importmagic-fix-imports)))
  shackra-before-save-py-importmagic-fix()
  run-hooks(before-save-hook)
  basic-save-buffer(t)
  save-buffer(1)
  funcall-interactively(save-buffer 1)
  call-interactively(save-buffer nil nil)
  command-execute(save-buffer)

shackra avatar Apr 09 '18 07:04 shackra

Sorry, didn't saw that reply that was before your last reply. Will provide that information soon

El 9 de abril de 2018 12:15:23 AM CST, Caibin Chen [email protected] escribió:

Sorry for late response.

For lsp-go: The go language server doesn't provide completion support. You can confirm it by M-x lsp-capabilities.

For lsp-python: It's unclear what went wrong. It's likely a bug in the code. I tried on my machine and it works well. Can you provide the following information for further debugging?

  1. Before opening any python file, M-x set-variable RET lsp-print-io RET t
  2. Open the problematic Python file, try completion
  3. Paste the content of the *Messages* buffer here
  4. Run M-x copmany-diag in the Python file with cursor after a dot, and paste the content of company-diag output here.

-- You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/tigersoldier/company-lsp/issues/31#issuecomment-379644885

-- Enviado desde mi dispositivo Android con K-9 Mail. Por favor, disculpa mi brevedad.

shackra avatar Apr 09 '18 07:04 shackra

Here is the information you requested. With lsp-print-io as t I open a Python file from one of my projects.

Can’t guess python-indent-offset, using defaults: 4
Switched to virtualenv: mcrc
next-line: End of buffer
Company: An error occurred in auto-begin
Wrong type argument: arrayp, nil

Then I position the cursor after the dot and call to company-diag.

Debugger entered--Lisp error: (wrong-type-argument arrayp nil)
  company-lsp(prefix)
  apply(company-lsp prefix)
  company--force-sync(company-lsp (prefix) company-lsp)
  company--multi-backend-adapter((company-lsp :with company-yasnippet) prefix)
  apply(company--multi-backend-adapter (company-lsp :with company-yasnippet) prefix)
  company-call-backend-raw(prefix)
  apply(company-call-backend-raw prefix)
  company--force-sync(company-call-backend-raw (prefix) (company-lsp :with company-yasnippet))
  company-call-backend(prefix)
  company-diag()
  funcall-interactively(company-diag)
  call-interactively(company-diag record nil)
  command-execute(company-diag record)
  #[257 "\304\305!\203\f�\306\307!!\210\307!\211\310\307!\311\")\207" [current-prefix-arg prefix-arg this-command real-this-command featurep smex smex-rank intern command-execute record] 4 "\n\n(fn CMD)"]("company-diag")
  ivy-call()
  ivy-read("M-x " [pulse-delete crux corral comment-dwim-2 delim-kill smartrep-original-position basic-c-compile debugger-previous-window realgud:gdb-frame-file-regexp c-chain-logic hl-indent smartrep-mode-line-string gnus-remove-header gold-mode helm-ack linear-subseq company-edbi fixmee-this-buffer-not-pristine-hook ac-emmet yaml-mode-map wl-highlight-summary-thread-top-face ahk-mode Serto\ Batnan DejaVu\ Sans\ Mono daemons all-the-icons-gnus no-tail fixmee-mode-major-mode save-delay add-node-modules-path Generate\ Source haskell-snippets hamburg-theme aria2 calt eldoc-overlay god-mode Insert\ try record-separator vimish-fold--vimish-overlay-p FUNC fixmee-reload M-wheel-up fixmee-last-good-hit py-yapf align-large-region STIX\ MathJax\ Monospace monokai-256-red-lc grep-a-lot Span\ a\ Cell\ to ...] :predicate commandp :require-match t :history counsel-M-x-history :action #[257 "\304\305!\203\f�\306\307!!\210\307!\211\310\307!\311\")\207" [current-prefix-arg prefix-arg this-command real-this-command featurep smex smex-rank intern command-execute record] 4 "\n\n(fn CMD)"] :sort t :keymap (keymap (67108908 . counsel--info-lookup-symbol) (67108910 . counsel-find-symbol)) :initial-input nil :caller counsel-M-x)
  counsel-M-x()
  funcall-interactively(counsel-M-x)
  call-interactively(counsel-M-x nil nil)
  command-execute(counsel-M-x)

Despite lsp-print-io set as t before visiting the Python file, *messages* has no messages coming from lsp-mode

shackra avatar Apr 14 '18 03:04 shackra

I said before that js2-mode worked fine with lsp-mode, it turns out tide-mode was providing the auto-completion at that time. If I turn off tide-mode and restart Emacs and try again auto-completion in js2-mode fails as well as in Python and the other programming languages.

shackra avatar Apr 14 '18 03:04 shackra

I ran bug-hunter in my configuration, and this was the result:

Initial tests done. Hunting for the cause...
"/home/jorge/puntoarchivos/emacs/.emacs.d/tmp-init.el", line 848 pos 0:
  The assertion returned the following value here:
    t
  Caused by the following expression:
    (use-package company-lsp :init
      (push 'company-lsp company-backends)
      (setf company-lsp-async t))

I decided to bisect further by setting company-lsp-async to nil, but it had no impact over the bug.

shackra avatar Apr 29 '18 21:04 shackra