harry0703/MoneyPrinterTurbo · error · BgmUploadError

background music file is empty

Error message

background music file is empty

What it means

Raised after the copy loop in stage_bgm_upload when total_bytes == 0, i.e. the uploaded source produced an EOF on the very first read. The temp file was created and fsynced but no content was written, so it is removed and BgmUploadError('background music file is empty') is raised. This rejects zero-byte uploads before FFmpeg validation ever runs.

Source

Thrown at app/services/bgm.py:213

            suffix=Path(safe_name).suffix.lower(),
            dir=target_dir,
        )
        with os.fdopen(descriptor, "wb") as output:
            while True:
                chunk = source.read(_COPY_CHUNK_BYTES)
                if not chunk:
                    break
                if not isinstance(chunk, (bytes, bytearray, memoryview)):
                    raise BgmUploadError("background music upload must be binary")
                total_bytes += len(chunk)
                if total_bytes > MAX_BGM_UPLOAD_BYTES:
                    raise BgmUploadError("background music file exceeds the 30 MB limit")
                output.write(chunk)
            output.flush()
            os.fsync(output.fileno())

        if total_bytes == 0:
            raise BgmUploadError("background music file is empty")
        return safe_name, temp_path, total_bytes
    except Exception as exc:
        _remove_staged_file(temp_path)
        if isinstance(exc, BgmUploadError):
            raise
        if isinstance(exc, OSError):
            raise BgmServiceError("failed to stage background music upload") from exc
        raise
    finally:
        # Streamlit 还需要使用同一个 UploadedFile 做浏览器试听;恢复文件指针可
        # 避免校验后播放器或最终保存读取到空内容。
        try:
            source.seek(0)
        except (AttributeError, OSError):
            pass


def validate_bgm_upload(filename: str, source: BinaryIO) -> str:

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Check the file size before calling the API (seek to end / os.fstat) and reject or skip empty files client-side.
  2. If the file object was previously read, call source.seek(0) before staging.
  3. Verify the upload is not a placeholder/dummy file created by the frontend on failure.

Example fix

// before
source.seek(0)  # missing -> EOF immediately
safe_name, temp_path, size = stage_bgm_upload(source, name)

// after
source.seek(0)
if isinstance(source, (io.RawIOBase, io.BufferedIOBase)) and not source.read(1):
    raise ValueError('empty upload')
source.seek(0)
safe_name, temp_path, size = stage_bgm_upload(source, name)
Defensive patterns

Strategy: validation

Validate before calling

fh.seek(0, os.SEEK_END)
size = fh.tell()
fh.seek(0)
if size == 0:
    raise ClientError('empty file')

Try / catch

try:
    stage_bgm_upload(fh, filename)
except BgmUploadError as e:
    if 'is empty' in str(e):
        show_user('The selected file is empty; re-export the audio')

Prevention

When it happens

Trigger: Submitting an empty (0-byte) file to the BGM upload endpoint, or a file-like object already at EOF because a previous validation pass consumed it without seeking back to 0.

Common situations: Front-end bug sending an empty FormData part; the same UploadedFile read twice without seek(0) — note stage_bgm_upload itself restores the pointer in finally, but other code that reads first may not; truncated uploads from flaky networks.

Related errors


AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14). Data as JSON: /api/errors/0d9bb57297242b54. Report an issue: GitHub.