task: metadata: install: pip install -e .[dev]
patch: diff --git a/AUTHORS.rst b/AUTHORS.rst
index 7ff39b06e..8a66e5b08 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -137,7 +137,7 @@ Some other past or present contributors are:
 * `Maximilian Cosmo Sitter`_
 * `Mehdi Rahim`_: Air Liquide, France
 * `Michael Eickenberg`_: Flatiron Institute, New-York, New-York, USA
-* `Michael Hanke`_: Psycho­informatics, Forschungszentrum Jülich GmbH, Jülich, Germany
+* `Michael Hanke`_: Psychoinformatics, Forschungszentrum Jülich GmbH, Jülich, Germany
 * `Michael Notter`_: ams OSRAM, Martigny, Lausanne, Switzerland
 * `Michael Waskom`_: Flatiron health, New York, USA
 * `Michelle Wang`_: Origami lab, McGill University, Montréal, Canada
diff --git a/CITATION.cff b/CITATION.cff
index d981d6c93..663068679 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -27,6 +27,7 @@ contact:
 license: BSD-4-Clause
 
 authors:
+  - family-names: Nilearn contributors
   - given-names: Ahmad
     family-names: Chamma
     website: https://github.com/achamma723
@@ -419,7 +420,7 @@ authors:
     family-names: Hanke
     website: https://github.com/mih
     email: michael.hanke@gmail.com
-    affiliation: Psycho­informatics, Forschungszentrum Jülich GmbH, Jülich, Germany
+    affiliation: Psychoinformatics, Forschungszentrum Jülich GmbH, Jülich, Germany
     orcid: https://orcid.org/0000-0001-6398-6370
   - given-names: Michael
     family-names: Notter
@@ -640,3 +641,8 @@ authors:
     family-names: Nájera
     website: https://github.com/Titan-C
     affiliation: Checkmk
+  - given-names: Alexandre
+    family-names: Cionca
+    website: https://github.com/acionca
+    affiliation: Centre Hospitalier Universitaire Vaudoise, Lausanne, Switzerland
+    orcid: https://orcid.org/0000-0002-1910-9650
diff --git a/maint_tools/citation_cff_maint.py b/maint_tools/citation_cff_maint.py
index 8b1bb1994..9fab548d8 100644
--- a/maint_tools/citation_cff_maint.py
+++ b/maint_tools/citation_cff_maint.py
@@ -181,9 +181,25 @@ def count_authors() -> int:
     return nb_authors
 
 
+def remove_consortium(authors: list[dict[str, str]]) -> list[dict[str, str]]:
+    """Remove consortium from authors."""
+    authors = [
+        author
+        for author in authors
+        if author["family-names"] != "Nilearn contributors"
+    ]
+    return authors
+
+
+def add_consortium(authors: list[dict[str, str]]) -> list[dict[str, str]]:
+    """Add consortium to authors."""
+    return [{"family-names": "Nilearn contributors"}] + authors
+
+
 def main():
     """Update names.rst and AUTHORS.rst files."""
     citation = read_citation_cff()
+    citation["authors"] = remove_consortium(citation["authors"])
     citation["authors"] = sort_authors(citation["authors"])
 
     nb_authors = count_authors()
@@ -192,10 +208,11 @@ def main():
     # Sanity check to make sure we have not lost anyone
     assert nb_authors <= new_nb_authors
 
-    write_citation_cff(citation)
-
     write_authors_file(citation["authors"])
 
+    citation["authors"] = add_consortium(citation["authors"])
+    write_citation_cff(citation)
+
 
 if __name__ == "__main__":
     main()
diff --git a/nilearn/maskers/multi_nifti_labels_masker.py b/nilearn/maskers/multi_nifti_labels_masker.py
index dc3258b75..89eeaecdd 100644
--- a/nilearn/maskers/multi_nifti_labels_masker.py
+++ b/nilearn/maskers/multi_nifti_labels_masker.py
@@ -188,11 +188,14 @@ class MultiNiftiLabelsMasker(NiftiLabelsMasker):
         if confounds is None:
             confounds = itertools.repeat(None, len(imgs_list))
 
+        if sample_mask is None:
+            sample_mask = itertools.repeat(None, len(imgs_list))
+
         func = self._cache(self.transform_single_imgs)
 
         region_signals = Parallel(n_jobs=n_jobs)(
-            delayed(func)(imgs=imgs, confounds=cfs, sample_mask=sample_mask)
-            for imgs, cfs in zip(niimg_iter, confounds)
+            delayed(func)(imgs=imgs, confounds=cfs, sample_mask=sms)
+            for imgs, cfs, sms in zip(niimg_iter, confounds, sample_mask)
         )
         return region_signals
 
diff --git a/nilearn/maskers/multi_nifti_maps_masker.py b/nilearn/maskers/multi_nifti_maps_masker.py
index 461fc85aa..c81b01c46 100644
--- a/nilearn/maskers/multi_nifti_maps_masker.py
+++ b/nilearn/maskers/multi_nifti_maps_masker.py
@@ -182,11 +182,14 @@ class MultiNiftiMapsMasker(NiftiMapsMasker):
         if confounds is None:
             confounds = itertools.repeat(None, len(imgs_list))
 
+        if sample_mask is None:
+            sample_mask = itertools.repeat(None, len(imgs_list))
+
         func = self._cache(self.transform_single_imgs)
 
         region_signals = Parallel(n_jobs=n_jobs)(
-            delayed(func)(imgs=imgs, confounds=cfs, sample_mask=sample_mask)
-            for imgs, cfs in zip(niimg_iter, confounds)
+            delayed(func)(imgs=imgs, confounds=cfs, sample_mask=sms)
+            for imgs, cfs, sms in zip(niimg_iter, confounds, sample_mask)
         )
         return region_signals
 

problem_statement: [BUG]  Can't use MultiNiftiMapsMasker with a list of sample_mask
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Operating system

- [X] Linux
- [ ] Mac
- [ ] Windows

### Operating system version

Linux Ubuntu 20.04

### Python version

- [ ] 3.11
- [ ] 3.10
- [ ] 3.9
- [X] 3.8
- [ ] 3.7

### nilearn version

0.10.1

### Expected behavior

I am using `MultiNiftiMapsMasker` with multiple sample_mask (obtained from `load_confounds` with multiple input files) and I believe it should "distribute" the `sample_mask` to the appropriate parallel call of `transform_single_imgs`. However, it appears to only iterate over `niimg_iter` and `confounds`.

### Current behavior & error messages

This is what I got:
The parallel calls of `transform_single_imgs` always get the same `sample_mask` which is the same as the input of the `fit_transform` call (a list in this case) and raise an error. I believe (and confirm that) an iteration over the `sample_mask` (similar to the iteration over `niimg_iter` and `confounds`, [here](https://github.com/nilearn/nilearn/blob/0.10.1/nilearn/maskers/multi_nifti_maps_masker.py#L183C2-L186)) can fix this.


```bash
Traceback (most recent call last):
  File "nilearn_error.py", line 28, in <module>
    )
  File "/home/acionca/.local/lib/python3.8/site-packages/sklearn/utils/_set_output.py", line 140, in wrapped
    data_to_wrap = f(self, X, *args, **kwargs)
  File "/home/acionca/.local/lib/python3.8/site-packages/nilearn/maskers/nifti_maps_masker.py", line 421, in fit_transform
    return self.fit().transform(imgs, confounds=confounds,
  File "/home/acionca/.local/lib/python3.8/site-packages/sklearn/utils/_set_output.py", line 140, in wrapped
    data_to_wrap = f(self, X, *args, **kwargs)
  File "/home/acionca/.local/lib/python3.8/site-packages/nilearn/maskers/multi_nifti_maps_masker.py", line 209, in transform
    return self.transform_imgs(imgs, confounds, n_jobs=self.n_jobs,
  File "/home/acionca/.local/lib/python3.8/site-packages/nilearn/maskers/multi_nifti_maps_masker.py", line 183, in transform_imgs
    region_signals = Parallel(n_jobs=n_jobs)(
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 1952, in __call__
    return output if self.return_generator else list(output)
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 1595, in _get_outputs
    yield from self._retrieve()
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 1699, in _retrieve
    self._raise_error_fast()
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 1734, in _raise_error_fast
    error_job.get_result(self.timeout)
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 736, in get_result
    return self._return_or_raise()
  File "/home/acionca/.local/lib/python3.8/site-packages/joblib/parallel.py", line 754, in _return_or_raise
    raise self._result
ValueError: Number of sample_mask (2) not matching number of runs (1).
```


### Steps and code to reproduce bug

```python
from nilearn.datasets import fetch_atlas_difumo, fetch_development_fmri
from nilearn.interfaces.fmriprep import load_confounds
from nilearn.maskers import MultiNiftiMapsMasker

data = fetch_development_fmri(n_subjects=2, reduce_confounds=True)

fmri_filenames = data.func

atlas = fetch_atlas_difumo()
atlas_file = atlas.maps

confounds, sample_mask = load_confounds(
    fmri_filenames,
    strategy=["motion", "scrub"],
    motion="basic",
    scrub=5,
    fd_threshold=0.3,
)

masker = MultiNiftiMapsMasker(
    maps_img=atlas_file,
    standardize="zscore_sample",
    n_jobs=2,
)

time_series = masker.fit_transform(
    fmri_filenames, confounds=confounds, sample_mask=sample_mask
)
```

repo: nilearn/nilearn
test_cmd: pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
test_patch: diff --git a/doc/changes/latest.rst b/doc/changes/latest.rst
index 2ae41a5bb..41cf8b8a4 100644
--- a/doc/changes/latest.rst
+++ b/doc/changes/latest.rst
@@ -12,6 +12,8 @@ NEW
 
 Fixes
 -----
+Fix bug in method ``transform_imgs`` of :class:`~maskers.MultiNiftiMapsMasker` and :class:`~maskers.MultiNiftiLabelsMasker` that would raise an error if a list of ``sample_mask`` was specified to ``fit_transform`` (:gh:`3971` by `Alexandre Cionca`_).
+
 - Fix bug in ``nilearn.plotting.surf_plotting._plot_surf_matplotlib`` that would make vertices transparent when saving in PDF or SVG format (:gh:`3860` by `Mathieu Dugré`_).
 
 - Fix bug that would prevent using `symmetric_cmap=True` or the `avg_method` argument with :func:`~plotting.plot_surf_roi` (:gh:`3942` by `Rémi Gau`_).
diff --git a/nilearn/maskers/tests/test_multi_nifti_labels_masker.py b/nilearn/maskers/tests/test_multi_nifti_labels_masker.py
index 04ebc33e7..8647a600a 100644
--- a/nilearn/maskers/tests/test_multi_nifti_labels_masker.py
+++ b/nilearn/maskers/tests/test_multi_nifti_labels_masker.py
@@ -353,3 +353,38 @@ def test_multi_nifti_labels_masker_resampling():
         np.testing.assert_array_equal(
             get_data(compressed_img), get_data(compressed_img2)
         )
+
+
+def test_multi_nifti_labels_masker_list_of_sample_mask():
+    """Tests MultiNiftiLabelsMasker.fit_transform with a list of "sample_mask".
+
+    "sample_mask" was directly sent as input to the parallel calls of
+    "transform_single_imgs" instead of sending iterations.
+    See https://github.com/nilearn/nilearn/issues/3967 for more details.
+    """
+    shape1 = (13, 11, 12)
+    affine1 = np.eye(4)
+
+    n_regions = 9
+    length = 6
+    n_scrub1 = 3
+    n_scrub2 = 2
+
+    fmri11_img, mask11_img = data_gen.generate_fake_fmri(
+        shape1, affine=affine1, length=length
+    )
+
+    labels11_img = data_gen.generate_labeled_regions(
+        shape1, affine=affine1, n_regions=n_regions
+    )
+    sample_mask1 = np.arange(length - n_scrub1)
+    sample_mask2 = np.arange(length - n_scrub2)
+
+    masker = MultiNiftiLabelsMasker(labels11_img)
+    ts_list = masker.fit_transform(
+        [fmri11_img, fmri11_img], sample_mask=[sample_mask1, sample_mask2]
+    )
+
+    assert len(ts_list) == 2
+    for ts, n_scrub in zip(ts_list, [n_scrub1, n_scrub2]):
+        assert ts.shape == (length - n_scrub, n_regions)
diff --git a/nilearn/maskers/tests/test_multi_nifti_maps_masker.py b/nilearn/maskers/tests/test_multi_nifti_maps_masker.py
index ae3573b75..1612b0ce5 100644
--- a/nilearn/maskers/tests/test_multi_nifti_maps_masker.py
+++ b/nilearn/maskers/tests/test_multi_nifti_maps_masker.py
@@ -271,3 +271,36 @@ def test_multi_nifti_maps_masker_resampling():
             fmri11_img_r.affine, masker.maps_img_.affine
         )
         assert fmri11_img_r.shape == (masker.maps_img_.shape[:3] + (length,))
+
+
+def test_multi_nifti_maps_masker_list_of_sample_mask():
+    """Tests MultiNiftiMapsMasker.fit_transform with a list of "sample_mask".
+
+    "sample_mask" was directly sent as input to the parallel calls of
+    "transform_single_imgs" instead of sending iterations.
+    See https://github.com/nilearn/nilearn/issues/3967 for more details.
+    """
+    shape1 = (13, 11, 12)
+    affine1 = np.eye(4)
+
+    n_regions = 9
+    length = 6
+    n_scrub1 = 3
+    n_scrub2 = 2
+
+    fmri11_img, mask11_img = data_gen.generate_fake_fmri(
+        shape1, affine=affine1, length=length
+    )
+
+    maps11_img, _ = data_gen.generate_maps(shape1, n_regions, affine=affine1)
+    sample_mask1 = np.arange(length - n_scrub1)
+    sample_mask2 = np.arange(length - n_scrub2)
+
+    masker = MultiNiftiMapsMasker(maps11_img)
+    ts_list = masker.fit_transform(
+        [fmri11_img, fmri11_img], sample_mask=[sample_mask1, sample_mask2]
+    )
+
+    assert len(ts_list) == 2
+    for ts, n_scrub in zip(ts_list, [n_scrub1, n_scrub2]):
+        assert ts.shape == (length - n_scrub, n_regions)