From b00672d4a273a0cf275b0311181c5f2959600c57 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Wed, 21 Oct 2026 11:09:05 +0700 Subject: [PATCH 1/2] fix: load StarNodes INT8 ConvRot metadata --- src/model_io/safetensors_io.cpp | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/model_io/safetensors_io.cpp b/src/model_io/safetensors_io.cpp index cf424af92..41d84154c 100644 --- a/src/model_io/safetensors_io.cpp +++ b/src/model_io/safetensors_io.cpp @@ -247,6 +247,46 @@ bool read_safetensors_file(const std::string& file_path, comfy_quant_configs.emplace(module_name, std::move(config)); } + // StarNodes stores INT8 ConvRot configuration in safetensors file metadata + // rather than in per-layer .comfy_quant tensors. + auto metadata_item = header_.find("__metadata__"); + if (metadata_item != header_.end() && metadata_item->is_object()) { + auto quantization_item = metadata_item->find("_quantization_metadata"); + if (quantization_item != metadata_item->end() && quantization_item->is_string()) { + try { + const nlohmann::json quantization = nlohmann::json::parse(quantization_item->get()); + auto layers = quantization.find("layers"); + if (layers != quantization.end() && layers->is_object()) { + const std::string format = quantization.value("format", ""); + for (const auto& layer : layers->items()) { + const std::string& module_name = layer.key(); + if (!layer.value().is_object() || + header_.find(module_name + ".weight") == header_.end() || + header_.find(module_name + ".weight_scale") == header_.end() || + comfy_quant_configs.find(module_name) != comfy_quant_configs.end()) { + continue; + } + + ComfyQuantConfig config; + config.format = layer.value().value("format", format); + config.convrot = config.format == "int8_convrot" || layer.value().value("convrot", false); + config.group_size = layer.value().value("convrot_groupsize", + layer.value().value("group_size", 0)); + if (config.format == "int8_convrot") { + config.format = "int8_tensorwise"; + } + if (config.format == "int8_tensorwise") { + comfy_quant_configs.emplace(module_name, std::move(config)); + } + } + } + } catch (const std::exception&) { + set_error(error, "parsing StarNodes quantization metadata failed: '" + file_path + "'"); + return false; + } + } + } + tensor_storages.clear(); for (auto& item : header_.items()) { std::string name = item.key(); From 58a294896675da8f4683972bd711dc53bbc859bf Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Wed, 21 Oct 2026 11:20:49 +0700 Subject: [PATCH 2/2] Implement error handling for int8_tensorwise format Add error handling for unsupported int8_tensorwise format Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/model_io/safetensors_io.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/model_io/safetensors_io.cpp b/src/model_io/safetensors_io.cpp index 41d84154c..dfffda7a1 100644 --- a/src/model_io/safetensors_io.cpp +++ b/src/model_io/safetensors_io.cpp @@ -276,6 +276,10 @@ bool read_safetensors_file(const std::string& file_path, config.format = "int8_tensorwise"; } if (config.format == "int8_tensorwise") { +#ifdef SD_USE_UPSTREAM_GGML + set_error(error, "INT8 tensorwise/convrot is not supported by this ggml build (tensor '" + module_name + ".weight')"); + return false; +#endif comfy_quant_configs.emplace(module_name, std::move(config)); } }