{"record":{"id":"b07e87a5a7108cee","repo":"ruvnet/RuView","slug":"service-service-name-not-available","errorCode":null,"errorMessage":"Service '{service_name}' not available","messagePattern":"Service '(.+?)' not available","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"archive/v1/src/api/dependencies.py","lineNumber":272,"sourceCode":"    request: Request,\n    service_name: str\n) -> bool:\n    \"\"\"Check if a service is healthy.\"\"\"\n    try:\n        if service_name == \"pose\":\n            service = getattr(request.app.state, 'pose_service', None)\n        elif service_name == \"stream\":\n            service = getattr(request.app.state, 'stream_service', None)\n        elif service_name == \"hardware\":\n            service = getattr(request.app.state, 'hardware_service', None)\n        else:\n            raise HTTPException(\n                status_code=status.HTTP_400_BAD_REQUEST,\n                detail=f\"Unknown service: {service_name}\"\n            )\n        \n        if not service:\n            raise HTTPException(\n                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,\n                detail=f\"Service '{service_name}' not available\"\n            )\n        \n        # Check service health\n        status_info = await service.get_status()\n        if status_info.get(\"status\") != \"healthy\":\n            raise HTTPException(\n                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,\n                detail=f\"Service '{service_name}' is unhealthy: {status_info.get('error', 'Unknown error')}\"\n            )\n        \n        return True\n        \n    except HTTPException:\n        raise\n    except Exception as e:\n        logger.error(f\"Error checking service health for {service_name}: {e}\")","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/archive/v1/src/api/dependencies.py#L254-L290","documentation":"check_service_health raises 503 \"Service '<name>' not available\" when the service name is recognized but the corresponding app.state attribute (pose_service/stream_service/hardware_service) is None — the service was never attached at startup. The route exists, but the backing service object does not.","triggerScenarios":"A health-check request racing app startup before the lifespan handler attached services; service initialization failed or was skipped (e.g. no hardware present) leaving the attribute None; a partially initialized app where only some services were constructed.","commonSituations":"Kubernetes readiness probes hitting the port before startup completes; optional services disabled by config while their routes stay registered; swallowed startup exceptions leaving state attributes unset.","solutions":["Ensure the startup/lifespan code always sets app.state.pose_service/stream_service/hardware_service, even on degraded paths","Retry the health check after startup finishes; gate traffic on readiness, not liveness","If a service is intentionally disabled, return an explicit 'disabled' status instead of leaving the attribute None"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"# After startup, confirm the service is attached before relying on it\nasync def service_ready(app, attr: str, timeout: float = 10.0) -> bool:\n    deadline = time.monotonic() + timeout\n    while time.monotonic() < deadline:\n        if getattr(app.state, attr, None) is not None:\n            return True\n        await asyncio.sleep(0.2)\n    return False","typeGuard":null,"tryCatchPattern":"for attempt in range(5):\n    r = client.get('/api/health/pose')\n    if r.status_code == 200:\n        break\n    if r.status_code == 503 and 'not available' in r.json().get('detail', ''):\n        await asyncio.sleep(2 ** attempt)  # service not initialized yet: back off and retry\n        continue\n    r.raise_for_status()","preventionTips":["Gate traffic on the health endpoint (readiness) rather than the port being open","Always set app.state service attributes during startup, even on degraded paths","Return an explicit 'disabled' status for intentionally absent services instead of None"],"tags":["health-check","http-503","startup","python"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}