# Buggy code
def _extract_nc4_variable_encoding(
    variable,
    raise_on_invalid=False,
    lsd_okay=True,
    h5py_okay=False,
    backend="netCDF4",
    unlimited_dims=None,
):
    if unlimited_dims is None:
        unlimited_dims = ()

    encoding = variable.encoding.copy()

    safe_to_drop = set(["source", "original_shape"])
    valid_encodings = set(
        [
            "zlib",
            "complevel",
            "fletcher32",
            "contiguous",
            "chunksizes",
            "shuffle",
            "_FillValue",
            "dtype",
        ]
    )
    if lsd_okay:
        valid_encodings.add("least_significant_digit")
    if h5py_okay:
        valid_encodings.add("compression")
        valid_encodings.add("compression_opts")

    if not raise_on_invalid and encoding.get("chunksizes") is not None:
        # It's possible to get encoded chunksizes larger than a dimension size
        # if the original file had an unlimited dimension. This is problematic
        # if the new file no longer has an unlimited dimension.
        chunksizes = encoding["chunksizes"]
        chunks_too_big = any(
            c > d and dim not in unlimited_dims
            for c, d, dim in zip(chunksizes, variable.shape, variable.dims)
        )
        changed_shape = encoding.get("original_shape") != variable.shape
        if chunks_too_big or changed_shape:
            del encoding["chunksizes"]

    for k in safe_to_drop:
        if k in encoding:
            del encoding[k]

    if raise_on_invalid:
        invalid = [k for k in encoding if k not in valid_encodings]
        if invalid:
            raise ValueError(
                "unexpected encoding parameters for %r backend: %r. Valid "
                "encodings are: %r" % (backend, invalid, valid_encodings)
            )
    else:
        for k in list(encoding):
            if k not in valid_encodings:
                del encoding[k]

    return encoding


# Traceback (RuntimeError)
$ cat mwe.py
#!/usr/bin/env python3.6
import xarray

ds = xarray.open_dataset("sample.nc")
ds.to_netcdf("sample2.nc", unlimited_dims=["y"])
$ ncdump sample.nc
netcdf sample {
dimensions:
y = 6 ;
variables:
float x(y) ;
x:_FillValue = NaNf ;
int64 y(y) ;
data:

x = 0, 0, 0, 0, 0, 0 ;

y = 0, 1, 2, 3, 4, 5 ;
}
$ ./mwe.py
Traceback (most recent call last):
File "./mwe.py", line 5, in <module>
ds.to_netcdf("sample2.nc", unlimited_dims=["y"])
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/core/dataset.py", line 1133, in to_netcdf
unlimited_dims=unlimited_dims)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/api.py", line 627, in to_netcdf
unlimited_dims=unlimited_dims)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/core/dataset.py", line 1070, in dump_to_store
unlimited_dims=unlimited_dims)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/common.py", line 254, in store
*args, **kwargs)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/common.py", line 221, in store
unlimited_dims=unlimited_dims)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/netCDF4_.py", line 339, in set_variables
super(NetCDF4DataStore, self).set_variables(*args, **kwargs)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/common.py", line 233, in set_variables
name, v, check, unlimited_dims=unlimited_dims)
File "/dev/shm/gerrit/venv/stable-3.6/lib/python3.6/site-packages/xarray/backends/netCDF4_.py", line 385, in prepare_variable
fill_value=fill_value)
File "netCDF4/_netCDF4.pyx", line 2437, in netCDF4._netCDF4.Dataset.createVariable
File "netCDF4/_netCDF4.pyx", line 3439, in netCDF4._netCDF4.Variable.__init__
File "netCDF4/_netCDF4.pyx", line 1638, in netCDF4._netCDF4._ensure_nc_success
RuntimeError: NetCDF: Invalid argument

# Fixed code
def _extract_nc4_variable_encoding(
    variable,
    raise_on_invalid=False,
    lsd_okay=True,
    h5py_okay=False,
    backend="netCDF4",
    unlimited_dims=None,
):
    if unlimited_dims is None:
        unlimited_dims = ()

    encoding = variable.encoding.copy()

    safe_to_drop = set(["source", "original_shape"])
    valid_encodings = set(
        [
            "zlib",
            "complevel",
            "fletcher32",
            "contiguous",
            "chunksizes",
            "shuffle",
            "_FillValue",
            "dtype",
        ]
    )
    if lsd_okay:
        valid_encodings.add("least_significant_digit")
    if h5py_okay:
        valid_encodings.add("compression")
        valid_encodings.add("compression_opts")

    if not raise_on_invalid and encoding.get("chunksizes") is not None:
        # It's possible to get encoded chunksizes larger than a dimension size
        # if the original file had an unlimited dimension. This is problematic
        # if the new file no longer has an unlimited dimension.
        chunksizes = encoding["chunksizes"]
        chunks_too_big = any(
            c > d and dim not in unlimited_dims
            for c, d, dim in zip(chunksizes, variable.shape, variable.dims)
        )
        changed_shape = encoding.get("original_shape") != variable.shape
        if chunks_too_big or changed_shape:
            del encoding["chunksizes"]

    var_has_unlim_dim = any(dim in unlimited_dims for dim in variable.dims)
    if not raise_on_invalid and var_has_unlim_dim and "contiguous" in encoding.keys():
        del encoding["contiguous"]

    for k in safe_to_drop:
        if k in encoding:
            del encoding[k]

    if raise_on_invalid:
        invalid = [k for k in encoding if k not in valid_encodings]
        if invalid:
            raise ValueError(
                "unexpected encoding parameters for %r backend: %r. Valid "
                "encodings are: %r" % (backend, invalid, valid_encodings)
            )
    else:
        for k in list(encoding):
            if k not in valid_encodings:
                del encoding[k]

    return encoding