# Buggy code
def encode_cf_variable(var, needs_copy=True, name=None):
    """
    Converts an Variable into an Variable which follows some
    of the CF conventions:

        - Nans are masked using _FillValue (or the deprecated missing_value)
        - Rescaling via: scale_factor and add_offset
        - datetimes are converted to the CF 'units since time' format
        - dtype encodings are enforced.

    Parameters
    ----------
    var : xarray.Variable
        A variable holding un-encoded data.

    Returns
    -------
    out : xarray.Variable
        A variable which has been encoded as described above.
    """
    var = maybe_encode_datetime(var, name=name)
    var = maybe_encode_timedelta(var, name=name)
    var, needs_copy = maybe_encode_offset_and_scale(var, needs_copy, name=name)
    var, needs_copy = maybe_encode_fill_value(var, needs_copy, name=name)
    var = maybe_encode_nonstring_dtype(var, name=name)
    var = maybe_default_fill_value(var)
    var = maybe_encode_bools(var)
    var = ensure_dtype_not_object(var, name=name)
    var = maybe_encode_string_dtype(var, name=name)
    return var


# Traceback (UnboundLocalError)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-26-2052b95f2d95> in <module>()
----> 1 no2 = xr.open_dataset(product, group='/PRODUCT')

/Users/stefano/anaconda/lib/python3.6/site-packages/xarray/backends/api.py in open_dataset(filename_or_obj, group, decode_cf, mask_and_scale, decode_times, autoclose, concat_characters, decode_coords, engine, chunks, lock, cache, drop_variables)
303             lock = _default_lock(filename_or_obj, engine)
304         with close_on_error(store):
--> 305             return maybe_decode_store(store, lock)
306     else:
307         if engine is not None and engine != 'scipy':

/Users/stefano/anaconda/lib/python3.6/site-packages/xarray/backends/api.py in maybe_decode_store(store, lock)
223             store, mask_and_scale=mask_and_scale, decode_times=decode_times,
224             concat_characters=concat_characters, decode_coords=decode_coords,
--> 225             drop_variables=drop_variables)
226
227         _protect_dataset_variables_inplace(ds, cache)

/Users/stefano/anaconda/lib/python3.6/site-packages/xarray/conventions.py in decode_cf(obj, concat_characters, mask_and_scale, decode_times, decode_coords, drop_variables)
1153     vars, attrs, coord_names = decode_cf_variables(
1154         vars, attrs, concat_characters, mask_and_scale, decode_times,
-> 1155         decode_coords, drop_variables=drop_variables)
1156     ds = Dataset(vars, attrs=attrs)
1157     ds = ds.set_coords(coord_names.union(extra_coords).intersection(vars))

/Users/stefano/anaconda/lib/python3.6/site-packages/xarray/conventions.py in decode_cf_variables(variables, attributes, concat_characters, mask_and_scale, decode_times, decode_coords, drop_variables)
1086             k, v, concat_characters=concat_characters,
1087             mask_and_scale=mask_and_scale, decode_times=decode_times,
-> 1088             stack_char_dim=stack_char_dim)
1089         if decode_coords:
1090             var_attrs = new_vars[k].attrs

/Users/stefano/anaconda/lib/python3.6/site-packages/xarray/conventions.py in decode_cf_variable(name, var, concat_characters, mask_and_scale, decode_times, decode_endianness, stack_char_dim)
998         if (has_fill or scale_factor is not None or add_offset is not None):
999             if has_fill and np.array(fill_value).dtype.kind in ['U', 'S', 'O']:
-> 1000                 if string_encoding is not None:
1001                     raise NotImplementedError(
1002                         'variable %r has a _FillValue specified, but '

UnboundLocalError: local variable 'string_encoding' referenced before assignment

# Fixed code
def encode_cf_variable(var, needs_copy=True, name=None):
    """
    Converts an Variable into an Variable which follows some
    of the CF conventions:

        - Nans are masked using _FillValue (or the deprecated missing_value)
        - Rescaling via: scale_factor and add_offset
        - datetimes are converted to the CF 'units since time' format
        - dtype encodings are enforced.

    Parameters
    ----------
    var : xarray.Variable
        A variable holding un-encoded data.

    Returns
    -------
    out : xarray.Variable
        A variable which has been encoded as described above.
    """
    ensure_not_multiindex(var, name=name)

    for coder in [
        times.CFDatetimeCoder(),
        times.CFTimedeltaCoder(),
        variables.CFScaleOffsetCoder(),
        variables.CFMaskCoder(),
        variables.UnsignedIntegerCoder(),
    ]:
        var = coder.encode(var, name=name)

    # TODO(shoyer): convert all of these to use coders, too:
    var = maybe_encode_nonstring_dtype(var, name=name)
    var = maybe_default_fill_value(var)
    var = maybe_encode_bools(var)
    var = ensure_dtype_not_object(var, name=name)
    var = maybe_encode_string_dtype(var, name=name)
    return var