Repository navigation
fix: open model files with UTF-8 paths on Windows - #2144
Conversation
Paths reach the library as UTF-8 (argv_to_utf8 in the CLI, JSON in the server) but were opened with narrow APIs that Windows decodes in the ANSI code page: GetFileAttributesA/CreateFileA and std::fstream built from a std::string. A model under a non-ASCII directory could not be loaded. Open them through std::filesystem::u8path, as read_file_stamp already does, use the W APIs, and ggml_fopen for the GGUF writer.
|
Verified on the official master-970 release binaries (2f016e8) — this PR and companion #2145. Thank you. Datapoint (Windows 11, ANSI code page 1252, RX 6950 XT Vulkan, official Before (8cd731e): loading an SDXL checkpoint through a path with accented characters fails hard. Rig: a junction named with exit 1 — while the identical file loads fine through its non-accented path. Exactly the narrow-API ( After (2f016e8): the same accented path loads and renders normally, and the output at the same seed is pixel-identical to the ASCII-path run (0 differing pixels out of 262 144; the file hash differs only by the PNG metadata, which embeds the model path). The fix does not touch generation, as expected. Companion #2145 validated in the same run — its "before" behavior is nastier than a clean error, see the comment there. |
…to_claude Brings in the 20 upstream commits since 2988060 (2026-10-11): per-module automatic flash attention (leejet#2132), automatic direct convolution (leejet#2134, leejet#2141), reclaim before trusting wrapped Vulkan iGPU memory estimates (leejet#2124), UTF-8 file paths on Windows (leejet#2144, leejet#2145), FP8 CPU crash fix (leejet#2140), the ggml sync to dc99877 (leejet#2147), FLUX.3 Klein, MOSS-Image, the MoSR upscaler, MiniMax-H3 LoRAs, Qwen Image 2.1 Turbo preset, ROCm and MUSA Dockerfiles, documentation. Conflicts resolved, keeping both sides: - include/stable-diffusion.h: upstream's flash_attn_mode and conv_direct_mode stay right after conditioning_cache_size, so the layout up to there is still upstream's; memory_guard, disable_backend_fallback and multi_gpu follow. - src/core/ggml_extend_backend.cpp: upstream's new cuda_compiled_arch() keeps asking the compute capability through sd::cuda_driver (the driver is looked up at run time, so the engine starts where there is no NVIDIA driver), not through <cuda.h>; the HIP include from upstream is kept. - src/model_manager.cpp: the CPU memory guard and upstream's requires_reclamation rule are both applied: a Vulkan iGPU estimate that wrapped is reclaimed before it is trusted, and the guard still decides for the CPU backend. - src/model_loader.cpp: includes of both sides; load_worker keeps the file handle pool and the open retry. - examples/server/runtime.cpp: --degradation-cooldown check and upstream's u8path for the --serve-html-path check. - docs/backend.md: the "Several GPUs" section and upstream's "Direct convolution" and "Flash attention" sections. The ggml submodule moves from d25b121 to dc99877 (upstream's pin). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhZzDBkuuMp1jBf4WtEySC
Upstream now opens every model file through std::filesystem::u8path (leejet#2144) so that paths with non-ASCII characters work on Windows. The file handle pool opened its streams from the plain narrow string, which Windows reads in the ANSI code page, so the weights that stream from disk would still fail for such a path. The stamp the pool takes of the file already used u8path; the open now does too. On Linux u8path is the identity, so this can only be exercised on Windows. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhZzDBkuuMp1jBf4WtEySC
Companion of #2145 (the same fix in the CLI and server, for outputs and input images). The two PRs are independent and each builds on its own.
Problem
Paths reach the library as UTF-8: the CLI converts its arguments with
argv_to_utf8()and the server reads JSON. On Windows, the library thenopens them with narrow APIs that Windows decodes in the ANSI code page:
GetFileAttributesA/CreateFileA(file_exists,is_directory,MmapWrapper::create) andstd::ifstream/std::ofstream/std::fstreamconstructed from a
std::string. Any non-ASCII character in a path thennames a different file, so a model stored under e.g.
C:\Users\Hélène\orD:\modèles\cannot be loaded.read_file_stamp()inmodel_loader_files.cppalready usesstd::filesystem::u8path; this applies the same idiom to the other opens.Changes
src/core/util.cpp:file_exists,is_directoryandMmapWrapper::createuseGetFileAttributesW/CreateFileWonstd::filesystem::u8path(path).safetensors index and shard paths, the loader's non-mmap path),
--convertoutput, imatrix load/save, the HF tokenizer and tensordumps open their files through
std::filesystem::u8path(...).ggml_fopen, which already convertsUTF-8 to UTF-16 on Windows.
No public API change. On Linux/macOS
u8pathconstructs the same path asbefore.
Verification
Windows 11, MSVC 14.44,
-DSD_CUDA=OFF, master 8cd731e, FLUX.2 klein 4BQ4_0 (256x256, 4 steps, seed 1), the diffusion model hard-linked into a
directory named
modèles:--diffusion-model ...\modèles\klein.ggufloading diffusion model from '...' failed,get sd version from file failedKnown limitation
Zip-based torch checkpoints (
.ckpt/.pt) are opened by miniz, whichconverts UTF-8 to UTF-16 only under
_MSC_VER; a MinGW build still opensthem with narrow
fopen. That is inthirdparty/, so it is left out here.🤖 Generated with Claude Code
Summary by CodeRabbit