{"record":{"id":"65855366bf0d0028","repo":"unslothai/unsloth","slug":"chat-template-exceeds-the-max-chat-template-bytes-658553","errorCode":null,"errorMessage":"Chat template exceeds the {MAX_CHAT_TEMPLATE_BYTES}-byte limit.","messagePattern":"Chat template exceeds the (.+?)-byte limit\\.","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"warning","filePath":"studio/backend/routes/settings.py","lineNumber":713,"sourceCode":"    gpu_ids: Optional[list[int]] = Field(default = None, max_length = MAX_GPU_IDS)\n    # An all-default save carries no fields, like a forget; None keeps the legacy contract.\n    remove: Optional[bool] = None\n    # Fill in, don't replace: the backfill reads the map once then writes each model, so another\n    # tab's save was overwritten by this browser's older copy. Field level, not entry level: a\n    # legacy entry holds only some fields, and skipping it would strand the rest.\n    fill_absent_fields: bool = False\n\n    @field_validator(\"chat_template_override\")\n    @classmethod\n    def _limit_chat_template_bytes(cls, value: Optional[str]) -> Optional[str]:\n        # Mirrors LoadRequest.normalize_blank_chat_template_override.\n        if value is None:\n            return None\n        size = chat_template_byte_length(value)\n        if size is None:\n            raise ValueError(\"Chat template contains unpaired surrogate characters.\")\n        if size > MAX_CHAT_TEMPLATE_BYTES:\n            raise ValueError(f\"Chat template exceeds the {MAX_CHAT_TEMPLATE_BYTES}-byte limit.\")\n        return value\n\n    @field_validator(\n        \"max_seq_length\",\n        \"custom_context_length\",\n        \"spec_draft_n_max\",\n        \"n_parallel\",\n        \"n_batch\",\n        \"n_ubatch\",\n        \"gpu_layers\",\n        \"n_cpu_moe\",\n        \"gpu_ids\",\n        mode = \"before\",\n    )\n    @classmethod\n    def _no_booleans(cls, value: Any) -> Any:\n        # bool subclasses int and pydantic parses non-strictly, so `true` arrives as 1: a\n        # payload could pin GPU 1 or set a one-token context. _bounded_int rejects bools but","sourceCodeStart":695,"sourceCodeEnd":731,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/settings.py#L695-L731","documentation":"Pydantic validation failure (HTTP 422) from the same chat_template_override validator: chat_template_byte_length(value) succeeded but the UTF-8 byte size exceeds MAX_CHAT_TEMPLATE_BYTES. The limit is on encoded bytes, not characters, so multi-byte text (Jinja with non-ASCII literals) hits it earlier than a character count suggests.","triggerScenarios":"PUT the model-overrides payload with a chat template whose UTF-8 encoding exceeds the fixed byte cap — typically a large pasted Jinja template with whitespace or non-ASCII comments.","commonSituations":"Pasting the full template from a large model repo instead of only the differing part; templates with long HTML/whitespace; users counting characters instead of bytes.","solutions":["Shrink the template: remove comments/blank lines, or override only the needed blocks.","Compute the byte size with TextEncoder (JS) or len(s.encode('utf-8')) (Python) and stay under the limit before submitting.","If you truly need a larger template, raise MAX_CHAT_TEMPLATE_BYTES at the source and redeploy — but that is a server constant, not a request parameter."],"exampleFix":"# before\npayload = {'chat_template_override': template}  # len(template.encode()) > limit -> 422\n\n# after\nMAX = 65536  # mirror of MAX_CHAT_TEMPLATE_BYTES\nsize = len(template.encode('utf-8'))\nassert size <= MAX, f'{size} bytes exceeds {MAX}'\npayload = {'chat_template_override': template}","handlingStrategy":"validation","validationCode":"const bytes = new TextEncoder().encode(tpl).length;\nif (bytes > MAX_CHAT_TEMPLATE_BYTES) {\n  throw new Error(`Template is ${bytes} bytes, limit ${MAX_CHAT_TEMPLATE_BYTES}`);\n}\nawait api.put(url, { chat_template_override: tpl });","typeGuard":"function templateWithinLimit(tpl: string, maxBytes: number): boolean {\n  return new TextEncoder().encode(tpl).length <= maxBytes;\n}","tryCatchPattern":"try { await api.put(url, { chat_template_override: tpl }); }\ncatch (e) {\n  if (e.status === 422 && /exceeds/.test(e.detail?.toString() ?? '')) { compactTemplate(); return; }\n  throw e;\n}","preventionTips":["Measure UTF-8 bytes, not character count.","Strip comments and collapse whitespace in pasted Jinja before saving.","Override only the differing template blocks instead of the whole file."],"tags":["pydantic","validation","http-422","size-limit","chat-template","utf-8"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}