{"record":{"id":"856c6e30d26ef213","repo":"unslothai/unsloth","slug":"hugging-face-token-cannot-be-empty","errorCode":null,"errorMessage":"Hugging Face token cannot be empty","messagePattern":"Hugging Face token cannot be empty","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"warning","filePath":"studio/backend/routes/settings.py","lineNumber":482,"sourceCode":"\nclass UploadLimitResponse(BaseModel):\n    max_upload_size_mb: int\n    max_upload_size_bytes: int\n    max_upload_size_label: str\n    default_upload_size_mb: int\n    min_upload_size_mb: int = MIN_UPLOAD_LIMIT_MB\n    max_allowed_upload_size_mb: int = MAX_UPLOAD_LIMIT_MB\n\n\nclass HuggingFaceTokenPayload(BaseModel):\n    token: str = Field(..., min_length = 1, max_length = 512)\n\n    @field_validator(\"token\")\n    @classmethod\n    def normalize_token(cls, value: str) -> str:\n        normalized = value.strip(\" \\t\\r\\n\\\"'\")\n        if not normalized:\n            raise ValueError(\"Hugging Face token cannot be empty\")\n        return normalized\n\n\nclass HuggingFaceTokenResponse(BaseModel):\n    token: Optional[str] = None\n    has_token: bool = False\n\n\n@router.get(\"/hugging-face-token\", response_model = HuggingFaceTokenResponse)\ndef get_hugging_face_token(\n    _current_subject: str = Depends(get_current_subject),\n    via_api_key: bool = Depends(authenticated_via_api_key),\n) -> HuggingFaceTokenResponse:\n    require_ui_session(via_api_key)\n    token = credential_secrets.get_hf_token()\n    return HuggingFaceTokenResponse(token = token, has_token = token is not None)\n\n","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/settings.py#L464-L500","documentation":"Pydantic validation failure (HTTP 422) from the field_validator on HuggingFaceTokenPayload.token. The validator strips whitespace AND quote characters (space, tab, CR, LF, double and single quotes) and rejects the token when nothing remains. The length guard (1-512) runs on the raw value, so a long quoted string can also fail the length check before normalization.","triggerScenarios":"PUT the Hugging Face token endpoint with a value that is only spaces/tabs/newlines, or only quote characters like \\\" \\\" or '' — e.g. copy-pasting with surrounding quotes from documentation or a CSV.","commonSituations":"User pastes '\"hf_abc...\"' wrapped in quotes from a notes app or shell export line; secrets manager injects an empty/whitespace env var into the form; user clears the field and submits.","solutions":["Paste the bare token (typically starts with 'hf_') with no surrounding quotes or whitespace.","Strip quotes/whitespace client-side before submit and validate non-empty.","If the token field is empty, skip the PUT entirely rather than sending an empty string."],"exampleFix":"// before\nawait api.put('/settings/hugging-face-token', { token: '\"  \"' }); // 422\n\n// after\nconst token = raw.trim().replace(/^[\"']|[\"']$/g, '').trim();\nif (!token) throw new Error('Token is empty');\nawait api.put('/settings/hugging-face-token', { token });","handlingStrategy":"validation","validationCode":"const token = raw.replace(/^[\\s\"']+|[\\s\"']+$/g, '');\nif (!token || token.length > 512) throw new Error('Token empty or too long');\nawait api.put('/settings/hugging-face-token', { token });","typeGuard":"function isValidHfToken(v: unknown): v is string {\n  if (typeof v !== 'string') return false;\n  const t = v.replace(/^[\\s\"']+|[\\s\"']+$/g, '');\n  return t.length >= 1 && t.length <= 512;\n}","tryCatchPattern":"try { await api.put('/settings/hugging-face-token', { token }); }\ncatch (e) {\n  if (e.status === 422) { showFieldError('token', 'Enter the bare token, no quotes/spaces'); return; }\n  throw e;\n}","preventionTips":["Paste bare tokens starting with 'hf_'; strip quotes/whitespace before submit.","Never send the PUT when the input is empty — clear via the dedicated delete flow if available.","Copy tokens from the HF settings page, not from quoted shell exports."],"tags":["pydantic","validation","http-422","hugging-face","secrets"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}