def check_provided_metadata_dict(metadata, ktk_cube_dataset_ids):
    """
    Check metadata dict provided by the user.

    Parameters
    ----------
    metadata: Optional[Dict[str, Dict[str, Any]]]
        Optional metadata provided by the user.
    ktk_cube_dataset_ids: Iterable[str]
        ktk_cube_dataset_ids announced by the user.

    Returns
    -------
    metadata: Dict[str, Dict[str, Any]]
        Metadata provided by the user.

    Raises
    ------
    TypeError: If either the dict or one of the contained values has the wrong type.
    ValueError: If a ktk_cube_dataset_id in the dict is not in ktk_cube_dataset_ids.
    """
    if metadata is None:
        metadata = {}
    elif not isinstance(metadata, dict):
        raise TypeError(
            "Provided metadata should be a dict but is {}".format(
                type(metadata).__name__
            )
        )

    unknown_ids = set(metadata.keys()) - set(ktk_cube_dataset_ids)
    if unknown_ids:
        raise ValueError(
            "Provided metadata for otherwise unspecified ktk_cube_dataset_ids: {}".format(
                ", ".join(sorted(unknown_ids))
            )
        )

    # sorted iteration for deterministic error messages
    for k in sorted(metadata.keys()):
        v = metadata[k]
        if not isinstance(v, dict):
            raise TypeError(
                "Provided metadata for dataset {} should be a dict but is {}".format(
                    k, type(v).__name__
                )
            )

    return metadata