{"record":{"id":"cbce780e19ecec37","repo":"fishaudio/fish-speech","slug":"invalid-token","errorCode":null,"errorMessage":"Invalid token","messagePattern":"Invalid token","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"tools/api_server.py","lineNumber":42,"sourceCode":"\npyrootutils.setup_root(__file__, indicator=\".project-root\", pythonpath=True)\n\nfrom tools.server.api_utils import MsgPackRequest, parse_args\nfrom tools.server.exception_handler import ExceptionHandler\nfrom tools.server.model_manager import ModelManager\nfrom tools.server.views import routes\n\nENV_ARGS_KEY = \"FISH_API_SERVER_ARGS\"\n\n\nclass API(ExceptionHandler):\n    def __init__(self, args: Namespace | None = None):\n        self.args = args or parse_args()\n\n        def api_auth(endpoint):\n            async def verify(token: Annotated[str, Depends(bearer_auth)]):\n                if token != self.args.api_key:\n                    raise HTTPException(401, None, \"Invalid token\")\n                return await endpoint()\n\n            async def passthrough():\n                return await endpoint()\n\n            if self.args.api_key is not None:\n                return verify\n            else:\n                return passthrough\n\n        self.routes = Routes(\n            routes,  # keep existing routes\n            http_middlewares=[api_auth],  # apply api_auth middleware\n        )\n\n        # OpenAPIの設定\n        self.openapi = OpenAPI(\n            Info(","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/fishaudio/fish-speech/blob/befe4001745417f8c42131739d862b8a6fdbd15a/tools/api_server.py#L24-L60","documentation":"The API server's bearer-token check compares the presented token against --api-key; on mismatch FastAPI returns 401 with detail 'Invalid token'. The check is only active when the server was started with an api_key.","triggerScenarios":"Calling any protected endpoint without an Authorization header or with a token different from the server's --api-key.","commonSituations":"Default client token vs custom server key; stale token after server restart with a new key; missing 'Bearer ' prefix in the header.","solutions":["Send header `Authorization: Bearer <same value as server --api-key>`","Restart the server without --api_key if auth is not needed (dev only)","Check for trailing whitespace/newlines when the key comes from an env var"],"exampleFix":"# before\nclient.set_api_key(\"wrong-key\")\n# after\nclient.set_api_key(os.environ[\"FISH_API_KEY\"])  # same value as server --api-key","handlingStrategy":"validation","validationCode":"import os\nassert args.api_key is None or os.environ.get(\"API_KEY\") == args.api_key","typeGuard":null,"tryCatchPattern":"try:\n    client.tts(...)\nexcept HTTPError as e:\n    if e.response.status_code == 401:\n        refresh_api_key()","preventionTips":["Load the key from the same env var on client and server","Send 'Authorization: Bearer <key>' with no extra whitespace"],"tags":["authentication","api-server","http-401"],"backgroundTag":"invalid-api-key","analyzedSha":"befe4001745417f8c42131739d862b8a6fdbd15a","analyzedAt":"2026-08-27T21:31:45.703Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}