Compare commits

...

7 Commits

Author SHA1 Message Date
Houde Li
2c65cc8bfb
Merge 0df0b0d613 into a3020f107e 2026-07-07 15:02:17 +02:00
Alexander Piskun
a3020f107e
fix(Video): don't crash on videos with undecodable audio streams (#14746)
* fix(Video): don't crash on videos with undecodable audio streams

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Update comfy_api_nodes/util/upload_helpers.py

---------

Signed-off-by: bigcat88 <bigcat88@icloud.com>
Co-authored-by: Alexis Rolland <alexisrolland@hotmail.com>
2026-07-07 15:59:49 +03:00
comfyanonymous
7cf4e78335
Delete symlink that breaks our updates. (#14803)
Some checks are pending
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
2026-07-06 22:24:05 -04:00
Alexis Rolland
7747c342d4
ci: add CLA Assistant workflow (#14582)
Some checks are pending
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
2026-07-07 06:44:19 +08:00
Houde
0df0b0d613 fix: address CodeRabbit review comments on PR #14587
- utils.py: add device param to _load_safetensors_no_mmap, move tensors
  to target device instead of always returning CPU tensors
- utils.py: validate read length == expected bytes; raise RuntimeError
  on partial/corrupt reads instead of silently creating empty tensors
- utils.py: scope no-mmap fallback to sys.platform == win32 to avoid
  unnecessary overhead on Linux/Mac CUDA systems; add sys import
- baselines: replace hardcoded LvHHu username with %USERPROFILE% in
  startup commands for portability

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:51:22 +01:00
Houde
e912b910a2 fix: add no-mmap safetensors loader for >4GB files on Windows ROCm/UMA
Root cause: Strix Halo UMA ROCm init reserves ~14 GB of Windows virtual
address space for GPU. This prevents safetensors from mmap-ing files
larger than ~4 GB (SDXL fp16 ~6.5 GB), causing access violations.
SD1.5 (3.97 GB) is below the threshold and unaffected.

Fix in comfy/utils.py:
- Add _LARGE_FILE_MMAP_THRESHOLD = 4_000_000_000
- Add _load_safetensors_no_mmap(): reads tensors via open()+seek()+read()
  instead of mmap, then clones each tensor for independent ownership
- In load_torch_file(): route files >4 GB with CUDA active through
  _load_safetensors_no_mmap() automatically

Tested: RealVisXL_V4.0.safetensors (6.46 GB) loads and generates
768x1024 portrait images at ~5 it/s on AMD Radeon 8050S (gfx1151).
SD1.5 baseline unaffected (still uses original mmap path).
2026-06-22 18:52:42 +01:00
Houde
b6a730b24e chore: add ROCm stable baseline snapshot (gfx1151 / Strix Halo)
- torch 2.7.0a0 + ROCm 6.5 via scottt/rocm-TheRock gfx1151 wheels
- numpy pinned to 1.26.4 for wheel compatibility
- SD1.5 512x512 20 steps ~5 it/s confirmed stable
- Saved workflow: sd15_test_rocm_workflow.json
- AMD Radeon 8050S, 14.37 GB UMA VRAM correctly detected
2026-06-22 18:52:42 +01:00
9 changed files with 437 additions and 5 deletions

91
.github/workflows/cla.yml vendored Normal file
View File

@ -0,0 +1,91 @@
name: CLA Assistant
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened, synchronize, closed]
permissions:
actions: write
contents: read # 'read' is enough because signatures live in a REMOTE repo
pull-requests: write
statuses: write
jobs:
cla-assistant:
runs-on: ubuntu-latest
steps:
# The CLA action normally requires every commit author in a PR to sign.
# We only want the PR author to sign, so we allowlist all other committers
# by computing them from the PR's commits and excluding the PR author.
- name: Build author-only allowlist
id: allowlist
if: >
github.event_name == 'pull_request_target' ||
(github.event_name == 'issue_comment' && github.event.issue.pull_request && (
github.event.comment.body == 'recheck' ||
github.event.comment.body == 'I have read and agree to the Contributor License Agreement'
))
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
PR_AUTHOR: ${{ github.event.pull_request.user.login || github.event.issue.user.login }}
BASE_ALLOWLIST: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
run: |
others=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/commits" --paginate \
--jq '.[] | (.author.login // empty), (.committer.login // empty)' \
| sort -u | grep -vix "${PR_AUTHOR}" | paste -sd, -)
if [ -n "$others" ]; then
echo "allowlist=${BASE_ALLOWLIST},${others}" >> "$GITHUB_OUTPUT"
else
echo "allowlist=${BASE_ALLOWLIST}" >> "$GITHUB_OUTPUT"
fi
- name: CLA Assistant
# Run on PR events, on "recheck" comment, or when someone posts the exact signing phrase.
# IMPORTANT: this phrase must match `custom-pr-sign-comment` below.
if: >
github.event_name == 'pull_request_target' ||
(github.event_name == 'issue_comment' && github.event.issue.pull_request && (
github.event.comment.body == 'recheck' ||
github.event.comment.body == 'I have read and agree to the Contributor License Agreement'
))
uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# PAT required to write to the centralized signatures repo.
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
# Where the CLA document lives (shown to contributors)
path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
# Centralized signature storage
remote-organization-name: comfy-org
remote-repository-name: comfy-cla
path-to-signatures: signatures/cla.json
branch: main
# Only the PR author must sign: bots plus every non-author committer
# are allowlisted via the "Build author-only allowlist" step above.
# *[bot] is a catch-all for any GitHub App bot account.
allowlist: ${{ steps.allowlist.outputs.allowlist }}
# Custom PR comment messages
custom-notsigned-prcomment: |
🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
custom-allsigned-prcomment: |
✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.

View File

@ -1 +0,0 @@
AGENTS.md

View File

@ -0,0 +1,83 @@
aiohappyeyeballs==2.6.2
aiohttp==3.14.1
aiosignal==1.4.0
alembic==1.18.4
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.13.0
attrs==26.1.0
av==17.1.0
blake3==1.0.8
certifi==2026.5.20
charset-normalizer==3.4.7
click==8.4.1
colorama==0.4.6
comfy-aimdo==0.4.9
comfy-kitchen==0.2.10
comfyui-embedded-docs==0.5.3
comfyui-workflow-templates-core==0.3.252
comfyui-workflow-templates-media-api==0.3.80
comfyui-workflow-templates-media-image==0.3.150
comfyui-workflow-templates-media-other==0.3.217
comfyui-workflow-templates-media-video==0.3.91
comfyui_frontend_package==1.45.15
comfyui_workflow_templates==0.9.98
einops==0.8.2
filelock==3.29.4
frozenlist==1.8.0
fsspec==2026.4.0
glfw==2.10.0
greenlet==3.5.1
h11==0.16.0
hf-xet==1.5.1
httpcore==1.0.9
httpx==0.28.1
huggingface_hub==1.19.0
idna==3.18
Jinja2==3.1.6
kornia==0.8.3
kornia_rs==0.1.14
Mako==1.3.12
markdown-it-py==4.2.0
MarkupSafe==3.0.3
mdurl==0.1.2
mpmath==1.3.0
multidict==6.7.1
networkx==3.6.1
numpy==1.26.4
packaging==26.2
pillow==12.2.0
propcache==0.5.2
psutil==7.2.2
pydantic==2.13.4
pydantic-settings==2.14.1
pydantic_core==2.46.4
Pygments==2.20.0
PyOpenGL==3.1.10
python-dotenv==1.2.2
PyYAML==6.0.3
regex==2026.5.9
requests==2.34.2
rich==15.0.0
safetensors==0.8.0
scipy==1.17.1
sentencepiece==0.2.1
setuptools==82.0.1
shellingham==1.5.4
simpleeval==1.0.7
spandrel==0.4.2
SQLAlchemy==2.0.50
sympy==1.14.0
tokenizers==0.22.2
torch @ https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch/torch-2.7.0a0+git3f903c3-cp312-cp312-win_amd64.whl#sha256=ab308d20b8568354781ceaad1c9a1637b6dff16ab42e589fa87b19fa87f3c839
torchaudio @ https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch/torchaudio-2.6.0a0+1a8f621-cp312-cp312-win_amd64.whl#sha256=caa1291b5040325d67ac2d6bddb9c3ec9478337dfc70a4d08bda8a557c834698
torchsde==0.2.6
torchvision @ https://github.com/scottt/rocm-TheRock/releases/download/v6.5.0rc-pytorch/torchvision-0.22.0+9eb57cd-cp312-cp312-win_amd64.whl#sha256=47fbcdc9b5e80ee7ab40c27bbf5cd36f7a7091eae3d43a09eebd833a391de1ec
tqdm==4.68.2
trampoline==0.1.2
transformers==5.12.0
typer==0.25.1
typing-inspection==0.4.2
typing_extensions==4.15.0
urllib3==2.7.0
yarl==1.24.2

36
baselines/system_info.txt Normal file
View File

@ -0,0 +1,36 @@
=== ComfyUI ROCm Stable Baseline ===
Date: 2026-06-20
--- Python ---
Python: 3.12.10
--- PyTorch / ROCm ---
torch: 2.7.0a0+git3f903c3
CUDA avail: True
Device: AMD Radeon(TM) 8050S Graphics
VRAM (GB): 14.37
ROCm/HIP: 6.5.25205-c1c2abe52
--- torch packages ---
torch: 2.7.0a0+git3f903c3
torchvision: 0.22.0+9eb57cd
torchaudio: 2.6.0a0+1a8f621
--- ComfyUI ---
Version: 0.24.0
Backend: ROCm 6.5 (scottt/rocm-TheRock gfx1151 wheel)
Tested: SD1.5 512x512 20steps ~5 it/s, stable
--- Wheel sources (gfx1151 / Strix Halo) ---
torch: scottt/rocm-TheRock v6.5.0rc-pytorch/torch-2.7.0a0+git3f903c3-cp312-cp312-win_amd64.whl
torchvision: scottt/rocm-TheRock v6.5.0rc-pytorch/torchvision-0.22.0+9eb57cd-cp312-cp312-win_amd64.whl
torchaudio: scottt/rocm-TheRock v6.5.0rc-pytorch/torchaudio-2.6.0a0+1a8f621-cp312-cp312-win_amd64.whl
numpy: pinned to <2 (1.26.4) for wheel compatibility
--- Startup ---
cd %USERPROFILE%\ComfyUI
.\\venv\\Scripts\\activate
python main.py
--- Saved workflow ---
baselines/workflows/sd15_test_rocm_workflow.json

View File

@ -0,0 +1,55 @@
=== ComfyUI RealVisXL no-mmap Stable Baseline ===
Date: 2026-06-20
--- Previous baseline ---
Tag: rocm-sd15-working-baseline (preserved, not modified)
--- This baseline adds ---
Fix: comfy/utils.py: _load_safetensors_no_mmap() for files >4 GB
Model: RealVisXL_V4.0.safetensors (6.46 GB) - path only, not in git
Test: 768x1024, 25 steps, cfg=6, dpmpp_2m, karras -> OK
--- Root cause of crash (diagnosed & fixed) ---
Strix Halo UMA: ROCm init reserves ~14 GB GPU virtual address space.
safetensors mmap of files >~4 GB then fails (Windows VA space exhausted).
SD1.5 (3.97 GB) < threshold -> mmap OK.
SDXL fp16 (~6.5 GB) > threshold -> access violation in safe_open().
Fix: sequential file-read (open+seek+read) bypasses mmap entirely.
--- Patch location ---
File: comfy/utils.py
Functions: _load_safetensors_no_mmap(), _LARGE_FILE_MMAP_THRESHOLD = 4_000_000_000
Branch: load_torch_file() elif os.path.getsize > threshold and cuda available
--- Startup command ---
cd %USERPROFILE%\ComfyUI
.\venv\Scripts\activate
python main.py --disable-dynamic-vram --disable-mmap
--- GPU / ROCm ---
torch: 2.7.0a0+git3f903c3
Device: AMD Radeon(TM) 8050S Graphics
VRAM GB: 14.37
ROCm: 6.5 / gfx1151 (Strix Halo)
--- Models in checkpoints (not in git) ---
v1-5-pruned-emaonly.safetensors 3.97 GB SD1.5 baseline
RealVisXL_V4.0.safetensors 6.46 GB SDXL realistic portrait
--- Working parameters (RealVisXL) ---
Resolution: 768x1024
Steps: 25
CFG: 6
Sampler: dpmpp_2m
Scheduler: karras
Batch size: 1
--- Recovery commands ---
# 1. Return to this code state:
git checkout rocm-realvisxl-nommap-working
# 2. Re-download RealVisXL if needed (not in git):
# python -c "from huggingface_hub import hf_hub_download; hf_hub_download(repo_id='SG161222/RealVisXL_V4.0', filename='RealVisXL_V4.0.safetensors', local_dir='models/checkpoints')"
# 3. Start ComfyUI:
# python main.py --disable-dynamic-vram --disable-mmap

View File

@ -0,0 +1,107 @@
{
"2": {
"inputs": {
"ckpt_name": "v1-5-pruned-emaonly.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Checkpoint加载器简易"
}
},
"3": {
"inputs": {
"text": "aa cute fluffy kitten, big round eyes, detailed fur, soft natural window light, cozy indoor background, shallow depth of field, photorealistic, high quality, 50mm lens",
"clip": [
"2",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP文本编码"
}
},
"4": {
"inputs": {
"text": "low quality, blurry, deformed, ugly, bad anatomy, distorted face, extra limbs, bad eyes, oversaturated",
"clip": [
"2",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP文本编码"
}
},
"5": {
"inputs": {
"width": 512,
"height": 512,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "空Latent图像"
}
},
"6": {
"inputs": {
"seed": 826325619577598,
"steps": 30,
"cfg": 7,
"sampler_name": "dpmpp_2m",
"scheduler": "normal",
"denoise": 1,
"model": [
"2",
0
],
"positive": [
"3",
0
],
"negative": [
"4",
0
],
"latent_image": [
"5",
0
]
},
"class_type": "KSampler",
"_meta": {
"title": "K采样器"
}
},
"7": {
"inputs": {
"samples": [
"6",
0
],
"vae": [
"2",
2
]
},
"class_type": "VAEDecode",
"_meta": {
"title": "VAE解码"
}
},
"8": {
"inputs": {
"filename_prefix": "ComfyUI",
"images": [
"7",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "保存图像"
}
}
}

View File

@ -22,6 +22,7 @@ import math
import struct
import ctypes
import os
import sys
import comfy.memory_management
import safetensors.torch
import numpy as np
@ -119,6 +120,40 @@ def load_safetensors(ckpt):
return sd, header.get("__metadata__", {}),
_LARGE_FILE_MMAP_THRESHOLD = 4_000_000_000 # 4 GB
def _load_safetensors_no_mmap(ckpt, device=None):
# Windows + ROCm/CUDA UMA: large mmaps fail after GPU virtual address space is reserved.
# Read tensors sequentially from file instead.
if device is None:
device = torch.device("cpu")
sd = {}
with open(ckpt, "rb") as fh:
header_len = struct.unpack("<Q", fh.read(8))[0]
header = json.loads(fh.read(header_len).decode("utf-8"))
data_start = 8 + header_len
for name, info in header.items():
if name == "__metadata__":
continue
start, end = info["data_offsets"]
dtype = _TYPES[info["dtype"]]
shape = info["shape"]
expected = end - start
if expected == 0:
sd[name] = torch.empty(shape, dtype=dtype, device=device)
continue
fh.seek(data_start + start)
raw = fh.read(expected)
if len(raw) != expected:
raise RuntimeError(
f"Safetensors read error: tensor '{name}' expected {expected} bytes, got {len(raw)}. "
f"File may be corrupt or truncated."
)
sd[name] = torch.frombuffer(bytearray(raw), dtype=dtype).reshape(shape).clone().to(device=device)
return sd, header.get("__metadata__", {})
def load_torch_file(ckpt, safe_load=False, device=None, return_metadata=False):
if device is None:
device = torch.device("cpu")
@ -129,6 +164,15 @@ def load_torch_file(ckpt, safe_load=False, device=None, return_metadata=False):
sd, metadata = load_safetensors(ckpt)
if not return_metadata:
metadata = None
elif (os.path.getsize(ckpt) > _LARGE_FILE_MMAP_THRESHOLD
and sys.platform == "win32"
and torch.cuda.is_available()):
# Windows ROCm/UMA: GPU init reserves ~14 GB of virtual address space,
# preventing mmap of files >4 GB. Use sequential file-read instead.
# Scoped to Windows only to avoid overhead on Linux/Mac CUDA systems.
sd, metadata = _load_safetensors_no_mmap(ckpt, device=device)
if not return_metadata:
metadata = None
else:
with safetensors.safe_open(ckpt, framework="pt", device=device.type) as f:
sd = {}

View File

@ -281,11 +281,18 @@ class VideoFromFile(VideoInput):
video_done = False
audio_done = True
if len(container.streams.audio):
audio_stream = container.streams.audio[-1]
# Use the last decodable audio stream. Streams FFmpeg has no decoder for have no codec context,
# and decoding their packets crashes the process. (e.g. APAC spatial-audio track in iPhone)
audio_stream = next(
(s for s in reversed(container.streams.audio) if s.codec_context is not None),
None,
)
if audio_stream is not None:
streams += [audio_stream]
resampler = av.audio.resampler.AudioResampler(format='fltp')
audio_done = False
elif len(container.streams.audio):
logging.warning("No decodable audio stream found in video; ignoring audio.")
for packet in container.demux(*streams):
if video_done and audio_done:
@ -457,10 +464,13 @@ class VideoFromFile(VideoInput):
else:
output_container.metadata[key] = json.dumps(value)
# Add streams to the new container
# Add streams to the new container. Streams with no codec context cannot be used as an output template.
stream_map = {}
for stream in streams:
if isinstance(stream, (av.VideoStream, av.AudioStream, SubtitleStream)):
if stream.codec_context is None:
logging.warning("Skipping %s stream %d with unsupported codec", stream.type, stream.index)
continue
out_stream = output_container.add_stream_from_template(template=stream, opaque=True)
stream_map[stream] = out_stream

View File

@ -158,7 +158,14 @@ async def upload_video_to_comfyapi(
# Convert VideoInput to BytesIO using specified container/codec
video_bytes_io = BytesIO()
video.save_to(video_bytes_io, format=container, codec=codec)
try:
video.save_to(video_bytes_io, format=container, codec=codec)
except Exception as e:
raise ValueError(
f"Could not convert the input video to {container.value.upper()} for upload; "
f"the file may be corrupted or use an unsupported codec. "
f"Try re-exporting it as MP4 (H.264). Original error: {e}"
) from e
video_bytes_io.seek(0)
return await upload_file_to_comfyapi(cls, video_bytes_io, filename, upload_mime_type, wait_label)