Skip to content

fix: avoid torchaudio shadowing in backend probe#1254

Closed
uzunenes wants to merge 3 commits intofishaudio:mainfrom
uzunenes:fix/torchaudio-backend-probe
Closed

fix: avoid torchaudio shadowing in backend probe#1254
uzunenes wants to merge 3 commits intofishaudio:mainfrom
uzunenes:fix/torchaudio-backend-probe

Conversation

@uzunenes
Copy link
Copy Markdown

This fixes a runtime UnboundLocalError caused by local shadowing of torchaudio
while probing the audio backend.

Reproduced with:

  • Docker image: fishaudio/fish-speech:server-cuda@sha256:458725b7bffa3e8def159ec90c5a2d8b73e1d8a83c7b110e5affc271032ef71e
uv run --no-sync tools/api_server.py \
	--listen 0.0.0.0:8080 \
	--device cuda \
	--half \
	--llama-checkpoint-path /app/checkpoints/s2-pro \
	--decoder-checkpoint-path /app/checkpoints/s2-pro/codec.pth \
	--decoder-config-name modded_dac_vq

The issue comes from this pattern inside local scope:

import torchaudio.io._load_audio_fileobj

That can break earlier access to torchaudio in the same scope with:

UnboundLocalError: cannot access local variable 'torchaudio' where it is not associated with a value

This PR replaces it with:

import importlib
importlib.import_module("torchaudio.io._load_audio_fileobj")

@uzunenes
Copy link
Copy Markdown
Author

Just a quick update: I tested this with the latest Docker image (server-cuda), and the same UnboundLocalError is still present.

Applying this exact fix resolves the issue completely, allowing the server to start and load the models without any problems.

Copy link
Copy Markdown
Contributor

@JiwaniZakir JiwaniZakir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix correctly addresses the shadowing issue — import torchaudio.io._load_audio_fileobj would bind torchaudio in the local namespace, potentially shadowing an earlier import, whereas importlib.import_module(...) avoids that side effect entirely.

One minor point: in both files, import importlib is placed inside the try block, which implies it could be the source of an ImportError — but importlib is a stdlib module and will never fail to import. Moving import importlib outside the try block (or to the top of the file with other imports) would more accurately communicate that only the importlib.import_module(...) call is the guarded operation.

Additionally, ModuleNotFoundError is a subclass of ImportError, so except (ImportError, ModuleNotFoundError) in both locations is redundant — except ImportError alone is sufficient and cleaner.

@uzunenes
Copy link
Copy Markdown
Author

Thanks for the review @JiwaniZakir . I moved importlib to the top-level imports and simplified the exception handling to catch only ImportError in both places.

@JiwaniZakir
Copy link
Copy Markdown
Contributor

The fix is correct — using a bare import torchaudio.io._load_audio_fileobj inside a local scope causes Python to treat torchaudio as a local name throughout that entire scope, breaking any earlier reference to the already-imported module. The importlib.import_module approach sidesteps this entirely without changing runtime behavior. Tested this pattern locally and the backend probe resolves cleanly without the UnboundLocalError.

@uzunenes uzunenes closed this by deleting the head repository Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants