If they are defined, they can override table-level settings.
Strings part_file_names;
    auto disks = getStoragePolicy()->getDisks();
    
    if (!getStoragePolicy()->isDefaultPolicy() && !skip_sanity_checks)
    {
        
        std::unordered_set<String> defined_disk_names;
        for (const auto & disk_ptr : disks)
            defined_disk_names.insert(disk_ptr->getName());
        for (const auto & [disk_name, disk] : getContext()->getDisksMap())
        {
            if (disk->isBroken())
                continue;
            if (!defined_disk_names.contains(disk_name) && disk->exists(relative_data_path))
            {
                for (const auto it = disk->iterateDirectory(relative_data_path); it->isValid(); it->next())
                {
                    if (MergeTreePartInfo::tryParsePartName(it->name(), format_version))
                        throw Exception(ErrorCodes::UNKNOWN_DISK,
                            "Part {} was found on disk {} which is not defined in the storage policy",
                            backQuote(it->name()), backQuote(disk_name));
                }
            }
        }
    }
    
    std::map<String, std::vector<std::pair<String, DiskPtr>>> disk_part_map;
    std::map<String, MutableDataPartsVector> disk_wal_part_map;
    ThreadPool pool(disks.size());
    std::mutex wal_init_lock;