{"record":{"id":"4be0d3f9720ca167","repo":"sgl-project/sglang","slug":"qwen-image-layered-requires-a-non-empty-image-path","errorCode":null,"errorMessage":"Qwen-Image-Layered requires a non-empty image_path.","messagePattern":"Qwen-Image-Layered requires a non-empty image_path\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/qwen_image_layered.py","lineNumber":64,"sourceCode":"\n    return fallback\n\n\ndef _seq_lens_from_optional_mask(\n    prompt_embeds: torch.Tensor, prompt_embeds_mask: torch.Tensor | None\n) -> list[int]:\n    \"\"\"Return real text lengths, treating a missing mask as all tokens valid.\"\"\"\n    if prompt_embeds_mask is None:\n        return [int(prompt_embeds.shape[1])] * int(prompt_embeds.shape[0])\n    return [int(x) for x in prompt_embeds_mask.sum(dim=1).tolist()]\n\n\ndef _resolve_layered_image_path(image_path: str | list[str]) -> str:\n    if isinstance(image_path, str):\n        return image_path\n    if isinstance(image_path, list) and image_path:\n        return image_path[0]\n    raise ValueError(\"Qwen-Image-Layered requires a non-empty image_path.\")\n\n\n# Copied from diffusers.pipelines.qwenimage.pipeline_qwenimage_edit_plus.calculate_dimensions\ndef calculate_dimensions(target_area, ratio):\n    width = math.sqrt(target_area * ratio)\n    height = width / ratio\n\n    width = round(width / 32) * 32\n    height = round(height / 32) * 32\n\n    return width, height\n\n\n# Copied from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_img2img.retrieve_latents\ndef retrieve_latents(\n    encoder_output: torch.Tensor,\n    generator: Optional[torch.Generator] = None,\n    sample_mode: str = \"sample\",","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/qwen_image_layered.py#L46-L82","documentation":"_resolve_layered_image_path normalizes the image_path input for Qwen-Image-Layered: a string is passed through, a non-empty list returns its first element, and everything else (empty list, None, wrong type) raises this error because layered image editing requires at least one reference image.","triggerScenarios":"Calling the layered stage's forward with image_path=[] (empty list), image_path=None, or a non-str/non-list value (e.g. an int or dict).","commonSituations":"Upstream image download/selection produced zero candidates and the empty list flowed through; conditionally building the image_path list and skipping the append branch; passing a Path object if it isn't coerced to str beforehand (type error path).","solutions":["Ensure image_path is a non-empty str or non-empty list[str] before calling forward.","Fix the upstream selection logic that yielded an empty list (check filenames, glob results, dataset fields).","Default to a meaningful fallback image or skip the request when no image is available."],"exampleFix":"# before\nstage.forward(image_path=[], ...)\n\n# after\nif not image_path:\n    raise SkipRequest(\"no reference image\")\nstage.forward(image_path=image_path, ...)","handlingStrategy":"type-guard","validationCode":"ip = kwargs.get(\"image_path\")\nassert isinstance(ip, str) or (isinstance(ip, list) and len(ip) > 0), \"image_path required\"","typeGuard":"def valid_image_path(ip) -> bool:\n    return isinstance(ip, str) and bool(ip) or isinstance(ip, list) and len(ip) > 0 and all(isinstance(x, str) for x in ip)","tryCatchPattern":"try:\n    out = stage.forward(...)\nexcept ValueError as e:\n    if \"non-empty image_path\" in str(e):\n        skip_or_fallback()\n    raise","preventionTips":["Validate file existence too (os.path.exists) at the data-loading layer.","Never construct image lists conditionally without a final emptiness check."],"tags":["qwen-image","layered-editing","image-path","validation"],"backgroundTag":"missing-required-input","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}