harry0703/MoneyPrinterTurbo · error · ValueError
max_age_days must be a positive integer or None
Error message
max_age_days must be a positive integer or None
What it means
ValueError from _validate_max_age_days in the cache manager: max_age_days must be None or a positive int, but the caller passed a non-int, a bool, zero, or a negative number. The explicit isinstance(max_age_days, bool) check rejects True/False even though bool subclasses int. Validation runs even when the cache directory is empty, so bad parameters fail deterministically instead of silently passing.
Source
Thrown at app/services/cache_manager.py:120
entry: _VideoCacheEntry,
max_age_days: int | None,
now: float,
) -> bool:
if max_age_days is None:
return True
return entry.mtime < now - max_age_days * _SECONDS_PER_DAY
def _validate_max_age_days(max_age_days: int | None) -> None:
"""即使缓存目录为空,也应稳定拒绝无效清理参数。"""
if max_age_days is None:
return
if (
isinstance(max_age_days, bool)
or not isinstance(max_age_days, int)
or max_age_days <= 0
):
raise ValueError("max_age_days must be a positive integer or None")
def get_video_cache_stats(max_age_days: int | None = None) -> VideoCacheStats:
"""
统计全部缓存,或预览修改时间早于指定天数的可清理缓存。
``max_age_days=None`` 表示全部缓存。统计过程只读取目录项的大小和修改时间,
不读取视频内容,因此即使缓存总容量很大也不会产生与容量成比例的 I/O。
"""
_validate_max_age_days(max_age_days)
now = time.time()
file_count = 0
total_size = 0
oldest_mtime = None
newest_mtime = None
for entry in _iter_video_cache_entries():View on GitHub (pinned to 1f9f19c202)
Solutions
- Pass None for 'all caches' and a positive int (e.g. 30) for age-based stats/cleanup.
- Coerce user input at the boundary: days = int(str(days)) and validate days > 0, or map falsy to None.
- Never rely on True/False — booleans are deliberately rejected.
Example fix
// before
get_video_cache_stats(max_age_days=request.args.get('days', type=float)) # 7.0 -> ValueError
// after
days = request.args.get('days', type=int)
get_video_cache_stats(max_age_days=days if days and days > 0 else None) Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_max_age_days(value):
if value is None:
return None
days = int(value)
if isinstance(value, bool) or days <= 0:
raise ValueError('max_age_days must be a positive integer or None')
return days Type guard
def is_valid_max_age_days(value) -> bool:
"""True only for None or positive non-bool ints."""
if value is None:
return True
return not isinstance(value, bool) and isinstance(value, int) and value > 0 Try / catch
try:
get_video_cache_stats(max_age_days=days)
except ValueError as e:
if 'max_age_days' in str(e):
days = None # fall back to full stats
get_video_cache_stats(max_age_days=days) Prevention
- Convert form/query params with type=int at the framework boundary.
- Use None (not 0) to mean 'all caches'.
- Never pass booleans — they are explicitly rejected because bool subclasses int.
When it happens
Trigger: Calling get_video_cache_stats(max_age_days=...), cleanup, or any API that funnels into _validate_max_age_days with 0, -1, 7.0, '7', or True. WebUI form values parsed as strings/floats are the classic source.
Common situations: Form/query params arriving as strings ('30') and being passed through unconverted; floats from division (days*1.0); using True as a truthy 'purge everything' flag; 0 intended to mean 'all' instead of None.
Related errors
- ElevenLabs video duration is invalid
- uploaded file must contain a decodable audio stream
- background music file is empty or missing
- background music file exceeds the 30 MB limit
- background music file is empty
AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14).
Data as JSON: /api/errors/a456ec9c12a1d87e.
Report an issue: GitHub.