# ValueError read\_raw\_eyelink missing channel name in annotations

**URL:** <https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846>\
**Category:** Support & Discussions\
**Tags:** preprocessing, eyetracking\
**Created:** [February 25, 2025, 5:43pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846 "2025-02-25T17:43:01Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![MargotSteijger](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/margotsteijger/32/4150_2.png) [@MargotSteijger](https://mne.discourse.group/u/MargotSteijger)\
**Post date:** [February 25, 2025, 5:43pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/1 "2025-02-25T17:43:01Z")

</div>

Hi,

I recently started using the mne toolbox for the preprocessing of my Eyelink pupil data and for most files this works fantastically, but I have a few files where the read\_raw\_eyelink function gives me the following error:

```python
Traceback (most recent call last):
  File "/home/msteijg/Desktop/topstore/2024_vanGaal_FMG-7251_NeuralArousal/Scripts/Scripts_eyetracker/0_preprocess_pupil_block.py", line 260, in <module>
    res = Parallel(n_jobs=n_jobs, verbose=1, backend='loky')(delayed(load_data)(filename, figs_dir) for filename in tqdm(asc_filenames))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/joblib/parallel.py", line 1918, in __call__
    return output if self.return_generator else list(output)
                                                ^^^^^^^^^^^^
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/joblib/parallel.py", line 1847, in _get_sequential_output
    res = func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^
  File "/home/msteijg/Desktop/topstore/2024_vanGaal_FMG-7251_NeuralArousal/Scripts/Scripts_eyetracker/0_preprocess_pupil_block.py", line 82, in load_data
    raw_et = mne.io.read_raw_eyelink(filename, verbose="CRITICAL")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/eyelink.py", line 59, in read_raw_eyelink
    raw_eyelink = RawEyelink(
                  ^^^^^^^^^^^
  File "<decorator-gen-204>", line 10, in __init__
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/eyelink.py", line 127, in __init__
    self.set_annotations(gap_annots + eye_annots)
  File "<decorator-gen-189>", line 12, in set_annotations
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/mne/io/base.py", line 747, in set_annotations
    new_annotations._prune_ch_names(self.info, on_missing)
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/mne/annotations.py", line 498, in _prune_ch_names
    _on_missing(
  File "/home/msteijg/pip3_analysis/lib/python3.12/site-packages/mne/utils/check.py", line 1218, in _on_missing
    raise error_klass(msg)
ValueError: At least one channel name in annotations missing from info: xpos_left

```

I checked the asc file that I feed to the function, but the data there looks fine. I think mne doesn’t recognize the channel names, but I can’t find where it gets it from, as xpos\_left is also not present in the asc file that does run normally.

I also tried to find other people with this problem, but I couldn’t find anyone with this error while loading pupil data, rather than EEG for example.

Anyone know how I can check if this channel is actually missing or if it isn’t read out properly?

Many thanks!!

The relevant code I use is

```python
# Convert edf to asc file
os.system('edf2asc {}'.format(edf_filename))

# Load asc as raw object
raw_et = mne.io.read_raw_eyelink(asc_filename)

```

- MNE version 1.9.0
- operating system: Linux
- Python version 3.12.3

---

<div class="post-metadata">

**Author:** ![scott-huberty](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/scott-huberty/32/2715_2.png) [@scott-huberty](https://mne.discourse.group/u/scott-huberty)\
**Post date:** [February 25, 2025, 6:24pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/2 "2025-02-25T18:24:12Z")

</div>

Hi @MargotSteijger

Is there any chance you can share the ASCII file? I developed the `read_raw_eyelink` function, and this would help me to identify the problem!

Scott

---

<div class="post-metadata">

**Author:** ![MargotSteijger](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/margotsteijger/32/4150_2.png) [@MargotSteijger](https://mne.discourse.group/u/MargotSteijger)\
**Post date:** [February 25, 2025, 7:36pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/3 "2025-02-25T19:36:11Z")

</div>

Thanks for your prompt response @scott-huberty !

Here is the link to one of the files that won’t run: [Eyelink\_testfile - Google Drive](https://drive.google.com/drive/folders/1z6n8PHWqFVhpzZJAtzl9yXl4HJ0q0j5_?usp=sharing)

---

<div class="post-metadata">

**Author:** ![scott-huberty](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/scott-huberty/32/2715_2.png) [@scott-huberty](https://mne.discourse.group/u/scott-huberty)\
**Post date:** [February 25, 2025, 8:12pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/4 "2025-02-25T20:12:01Z")

</div>

Hey @MargotSteijger I think the problem arises because in this recording, the eye that was being tracked switched from left to right midway through the recording, and our reader doesn’t know how to handle that.

We’ve seen this before, and I have a PR open to fix the issue: [BUG: read raw eyelink file that switches from binocular to monocular mode by scott-huberty · Pull Request #12847 · mne-tools/mne-python · GitHub](https://github.com/mne-tools/mne-python/pull/12847)

I’ll try to find some time in the next week or so to finish that PR.

Scott

---

<div class="post-metadata">

**Author:** ![MargotSteijger](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/margotsteijger/32/4150_2.png) [@MargotSteijger](https://mne.discourse.group/u/MargotSteijger)\
**Post date:** [February 25, 2025, 10:13pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/5 "2025-02-25T22:13:05Z")

</div>

Hi @scott-huberty

Thanks so much for having a look at it so fast! I checked the other files that gave this same error and I indeed see that there is a switch in left and right. I would never have thought of this as a potential issue. For now, I’ll write some code to change the word (most seem to flip before the actual experiment started), see if that gives me a (quick and) dirty solution. But I look forward to your fix!

Margot

---

<div class="post-metadata">

**Author:** ![MargotSteijger](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/margotsteijger/32/4150_2.png) [@MargotSteijger](https://mne.discourse.group/u/MargotSteijger)\
**Post date:** [February 26, 2025, 2:08pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/6 "2025-02-26T14:08:21Z")

</div>

Hi @scott-huberty,

I have another fun case that crashes the function 😅

This time, half way through the file, the HTARGET option of Eyelink was turned on so there are more columns to deal with. Just dropping the error and a link to the file here. Seems like a less easy fix than replacing some words (which worked for the eye flipping btw!)

File: [Eyelink\_htarget - Google Drive](https://drive.google.com/drive/folders/1CCWVqqeWfsOf0p-t8CrkriqO2xLB80Cq?usp=sharing)

```python
TypeError Traceback (most recent call last)
File ~/Desktop/topstore/2024_vanGaal_FMG-7251_NeuralArousal/Scripts/Scripts_eyetracker/0_preprocess_pupil_block.py:258
      0 <Error retrieving source code with stack_data see ipython/ipython#13598>

File ~/pip3_analysis/lib/python3.12/site-packages/joblib/parallel.py:1918, in Parallel. __call__ (self, iterable)
   1916 output = self._get_sequential_output(iterable)
   1917 next(output)
-> 1918 return output if self.return_generator else list(output)
   1920 # Let's create an ID that uniquely identifies the current call. If the
   1921 # call is interrupted early and that the same instance is immediately
   1922 # re-used, this id will be used to prevent workers that were
   1923 # concurrently finalizing a task from the previous call to run the
   1924 # callback.
   1925 with self._lock:

File ~/pip3_analysis/lib/python3.12/site-packages/joblib/parallel.py:1847, in Parallel._get_sequential_output(self, iterable)
   1845 self.n_dispatched_batches += 1
   1846 self.n_dispatched_tasks += 1
-> 1847 res = func(*args, **kwargs)
   1848 self.n_completed_tasks += 1
   1849 self.print_progress()

File ~/Desktop/topstore/2024_vanGaal_FMG-7251_NeuralArousal/Scripts/Scripts_eyetracker/0_preprocess_pupil_block.py:82, in load_data(filename, figs_dir)
     74 subj = os.path.basename(filename).split('_')[0]
     75 #ses = os.path.basename(filename).split('.')[0]
     76 #run = os.path.basename(filename).split('_')[-2]
     77 
   (...)
     80 # load pupil data:
     81 # try:
---> 82 raw_et = mne.io.read_raw_eyelink(filename)
     83 # except Exception as e:
     84 # print(e)
     85 # print(filename)
     86 # return filename
     88 raw_et._data[np.isnan(raw_et._data)] = 0

File ~/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/eyelink.py:59, in read_raw_eyelink(fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)
     29 """Reader for an Eyelink ``.asc`` file.
     30 
     31 Parameters
   (...)
     55 ``'BAD_ACQ_SKIP'``.
     56 """
     57 fname = _check_fname(fname, overwrite="read", must_exist=True, name="fname")
---> 59 raw_eyelink = RawEyelink(
     60 fname,
     61 create_annotations=create_annotations,
     62 apply_offsets=apply_offsets,
     63 find_overlaps=find_overlaps,
     64 overlap_threshold=overlap_threshold,
     65 verbose=verbose,
     66 )
     67 return raw_eyelink

File <decorator-gen-204>:12, in __init__ (self, fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)

File ~/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/eyelink.py:104, in RawEyelink. __init__ (self, fname, create_annotations, apply_offsets, find_overlaps, overlap_threshold, verbose)
    101 fname = Path(fname)
    103 # ======================== Parse ASCII file ==========================
--> 104 eye_ch_data, info, raw_extras = _parse_eyelink_ascii(
    105 fname, find_overlaps, overlap_threshold, apply_offsets
    106 )
    107 # ======================== Create Raw Object =========================
    108 super(). __init__ (
    109 info,
    110 preload=eye_ch_data,
   (...)
    113 raw_extras=[raw_extras],
    114 )

File ~/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/_utils.py:55, in _parse_eyelink_ascii(fname, find_overlaps, overlap_threshold, apply_offsets)
     52 _validate_data(raw_extras)
     54 # ======================== Create DataFrames ========================
---> 55 raw_extras["dfs"] = _create_dataframes(raw_extras, apply_offsets)
     56 del raw_extras["sample_lines"] # free up memory
     57 # add column names to dataframes and set the dtype of each column

File ~/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/_utils.py:281, in _create_dataframes(raw_extras, apply_offsets)
    279 # dataframe for samples
    280 df_dict["samples"] = pd.DataFrame(raw_extras["sample_lines"])
--> 281 df_dict["samples"] = _drop_status_col(df_dict["samples"]) # drop STATUS col
    283 # dataframe for each type of occular event
    284 for event, label in zip(
    285 ["EFIX", "ESACC", "EBLINK"], ["fixations", "saccades", "blinks"]
    286 ):

File ~/pip3_analysis/lib/python3.12/site-packages/mne/io/eyelink/_utils.py:341, in _drop_status_col(samples_df)
    339 # we know the first 3 columns will be the time, xpos, ypos
    340 for col in samples_df.columns[3:]:
--> 341 if samples_df[col][0][0].isnumeric():
    342 # if the value is numeric, it's not a status column
    343 continue
    344 if len(samples_df[col][0]) in [3, 5, 13, 17]:

TypeError: 'NoneType' object is not subscriptable

```

---

<div class="post-metadata">

**Author:** ![scott-huberty](https://yyz2.discourse-cdn.com/free1/user_avatar/mne.discourse.group/scott-huberty/32/2715_2.png) [@scott-huberty](https://mne.discourse.group/u/scott-huberty)\
**Post date:** [February 26, 2025, 3:41pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/7 "2025-02-26T15:41:16Z")

</div>

Aha 😅 thanks for sharing @MargotSteijger !!

So it seems that we _can’t_ assume that the channels present in an EyeLink file are static throughout the recording, which is indeed fun… I’ll set aside some time to see how easy this is to patch, in the next week or so.

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/mne/original/1X/85cc6bd2b69cb698a166dc6d880fb550510d0144.jpeg) [@system](https://mne.discourse.group/u/system)\
**Post date:** [March 5, 2025, 3:41pm UTC](https://mne.discourse.group/t/valueerror-read-raw-eyelink-missing-channel-name-in-annotations/10846/8 "2025-03-05T15:41:27Z")

</div>

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.
