harry0703/MoneyPrinterTurbo · error · SoniloError

Sonilo returned an invalid service list

Error message

Sonilo returned an invalid service list

What it means

Raised during the Sonilo connection test when the /v1/account/services response's 'available_services' field is not a JSON list of strings. The client treats the service list as a hard protocol contract: a list whose elements include non-strings (nulls, numbers, nested objects) fails validation even if the overall payload parsed as JSON. It aborts before checking whether the video-to-music service is present.

Source

Thrown at app/services/sonilo.py:114

        )
    except requests.RequestException as exc:
        raise SoniloError(f"failed to connect to Sonilo: {exc}") from exc
    if not response.ok:
        raise SoniloError(
            f"Sonilo connection failed ({response.status_code}): "
            f"{_safe_response_error(response)}"
        )
    try:
        payload = response.json()
    except ValueError as exc:
        raise SoniloError("Sonilo returned an invalid service response") from exc
    if not isinstance(payload, dict):
        raise SoniloError("Sonilo returned an unexpected service response")
    available_services = payload.get("available_services")
    if not isinstance(available_services, list) or not all(
        isinstance(service_id, str) for service_id in available_services
    ):
        raise SoniloError("Sonilo returned an invalid service list")
    normalized_services = {
        _normalize_service_id(service_id) for service_id in available_services
    }
    if VIDEO_TO_MUSIC_SERVICE_ID not in normalized_services:
        raise SoniloError("Sonilo video-to-music service is not available for this key")
    logger.info("Sonilo connection test succeeded")
    return payload


def _remove_file(file_path: str) -> None:
    """尽力清理 Sonilo 中间文件,不覆盖调用方正在处理的原始异常。"""
    if not file_path or not os.path.exists(file_path):
        return
    try:
        os.remove(file_path)
    except OSError as exc:
        logger.warning(
            f"failed to remove Sonilo temporary file: path={file_path}, error={exc}"

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Inspect the raw response body (log response.text before parsing) and compare its available_services shape against the documented list-of-strings contract.
  2. If the provider changed the schema, update the parsing in app/services/sonilo.py:114 to accept the new shape (for example extract service ids from a list of objects) while keeping the strict list-of-strings path.
  3. If a proxy or gateway is mangling the response, fix or bypass the proxy so the JSON reaches the client intact.
  4. If this came from a test stub, correct the fixture to return a list containing the string video_to_music.

Example fix

// stub/fixture before
{"available_services": [{"id": "video_to_music"}]}
// after
{"available_services": ["video_to_music"]}
Defensive patterns

Strategy: try-catch

Type guard

def is_valid_service_payload(payload: object) -> bool:
    return (
        isinstance(payload, dict)
        and isinstance(payload.get("available_services"), list)
        and all(isinstance(s, str) for s in payload["available_services"])
    )

Try / catch

try:
    sonilo.test_connection()
except SoniloError as exc:
    if "invalid service list" in str(exc):
        # provider schema drift: inspect raw response, do not retry blindly
        logger.error(f"Sonilo services schema changed: {exc}")
    raise

Prevention

When it happens

Trigger: Calling the Sonilo connection test (which GETs /v1/account/services) where the provider returns available_services as a list of objects like [{id: video_to_music}, null], or as a plain string instead of a list. Also triggered by API version changes that rename or restructure the field into a dict of quota objects.

Common situations: Provider ships an undocumented API revision; a proxy or gateway returns an HTML/JSON hybrid body that deserializes into unexpected shapes; a mock or stub server used in tests returns a simplified fixture without real string entries.

Related errors


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