{"record":{"id":"9872e9ae0a7f69be","repo":"harry0703/MoneyPrinterTurbo","slug":"sonilo-connection-failed-response-status-code","errorCode":null,"errorMessage":"Sonilo connection failed ({response.status_code}): {_safe_response_error(response)}","messagePattern":"Sonilo connection failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"SoniloError","httpStatus":null,"severity":"error","filePath":"app/services/sonilo.py","lineNumber":100,"sourceCode":"def test_connection() -> dict[str, Any]:\n    \"\"\"\n    使用不消耗配乐额度的服务列表接口验证 API Key。\n\n    返回原始 JSON 便于 UI 展示可用服务，但日志中绝不记录 Key 或请求头。\n    \"\"\"\n    api_key = get_api_key()\n    if not api_key:\n        raise SoniloError(\"Sonilo API key is required\")\n    try:\n        response = requests.get(\n            f\"{_base_url()}{SERVICES_PATH}\",\n            headers={\"Authorization\": f\"Bearer {api_key}\"},\n            timeout=(15, 30),\n        )\n    except requests.RequestException as exc:\n        raise SoniloError(f\"failed to connect to Sonilo: {exc}\") from exc\n    if not response.ok:\n        raise SoniloError(\n            f\"Sonilo connection failed ({response.status_code}): \"\n            f\"{_safe_response_error(response)}\"\n        )\n    try:\n        payload = response.json()\n    except ValueError as exc:\n        raise SoniloError(\"Sonilo returned an invalid service response\") from exc\n    if not isinstance(payload, dict):\n        raise SoniloError(\"Sonilo returned an unexpected service response\")\n    available_services = payload.get(\"available_services\")\n    if not isinstance(available_services, list) or not all(\n        isinstance(service_id, str) for service_id in available_services\n    ):\n        raise SoniloError(\"Sonilo returned an invalid service list\")\n    normalized_services = {\n        _normalize_service_id(service_id) for service_id in available_services\n    }\n    if VIDEO_TO_MUSIC_SERVICE_ID not in normalized_services:","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/sonilo.py#L82-L118","documentation":"Raised by sonilo.test_connection() when the services-list request completes but response.ok is False (HTTP status >= 400). The message includes the status code and up to 500 characters of the response body via _safe_response_error, so the exact server rejection (auth, quota, permission) is visible.","triggerScenarios":"GET {base_url}/v1/account/services returning 401/403 (invalid or revoked Sonilo API key, key lacking permission), 404 (wrong base_url or outdated SERVICES_PATH), 429 (rate limit), or 5xx (Sonilo server error).","commonSituations":"Expired or mistyped Sonolo API key; key from a different product tier without video_to_music access; sonilo_base_url pointing to a staging/gateway host with different routes; hitting rate limits during repeated connection tests; Sonilo-side incidents returning 502/503.","solutions":["Read the status code and body in the message: 401/403 → fix sonilo_api_key; 404 → fix sonilo_base_url; 429 → wait before retesting; 5xx → retry later","Regenerate the key in the Sonilo console if revoked, update config.toml/WebUI, re-run test_connection()","Confirm the key's subscription includes the video-to-music service (the endpoint lists services scoped to the key)","If a custom base_url is set, drop it to use the default https://api.sonilo.com"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"except SoniloError as e: parse the embedded status — retry only on 429/5xx with backoff; 401/403 → fix the key; 404 → fix base_url; surface _safe_response_error body to the user","preventionTips":["Use test_connection() to validate keys before starting paid generation tasks","Keep keys from a subscription that includes video_to_music","Avoid rapid repeated connection tests that trip rate limits"],"tags":["sonilo","http-error","api-key","authentication"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}