{"record":{"id":"bbb77646a72c0ecc","repo":"unslothai/unsloth","slug":"s3-config-requires-either-use-iam-role-true-or-bot","errorCode":null,"errorMessage":"s3_config requires either use_iam_role=True or both access_key_id and secret_access_key","messagePattern":"s3_config requires either use_iam_role=True or both access_key_id and secret_access_key","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"studio/backend/models/training.py","lineNumber":75,"sourceCode":"        alias = \"accessKeyId\",\n        description = \"AWS access key ID (optional if using IAM role)\",\n    )\n    secret_access_key: Optional[str] = Field(\n        None,\n        alias = \"secretAccessKey\",\n        description = \"AWS secret access key (optional if using IAM role)\",\n    )\n    use_iam_role: bool = Field(\n        False,\n        alias = \"useIamRole\",\n        description = \"Use IAM role credentials instead of access keys\",\n    )\n\n    @model_validator(mode = \"after\")\n    def _check_credentials(self) -> \"S3Config\":\n        # Require either IAM role auth or a full key pair so credentials are never half-configured.\n        if not self.use_iam_role and not (self.access_key_id and self.secret_access_key):\n            raise ValueError(\n                \"s3_config requires either use_iam_role=True or both \"\n                \"access_key_id and secret_access_key\"\n            )\n        return self\n\n\ndef _parse_lr(v: Any) -> float:\n    \"\"\"Parse learning_rate as a positive float strictly below _MAX_LR_VALUE.\"\"\"\n    if v is None:\n        raise ValueError(\"learning_rate is required\")\n    if isinstance(v, bool):\n        raise ValueError(\"learning_rate must be a number, not a bool\")\n    try:\n        lr = float(v)\n    except (TypeError, ValueError):\n        raise ValueError(f\"learning_rate must be parseable as float (got {v!r})\")\n    if not (lr > 0.0):\n        raise ValueError(f\"learning_rate must be > 0 (got {lr!r}); typical range is 1e-6 .. 1e-3\")","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/training.py#L57-L93","documentation":"Raised by the _check_credentials model_validator on S3Config in the training models. The S3 configuration must be complete in one of two ways: IAM role auth (use_iam_role=True) or a full access-key pair (both access_key_id and secret_access_key). This prevents half-configured credentials that would otherwise fail later at upload time with confusing AWS SDK errors. Truthiness is used, so an empty-string key also triggers the error.","triggerScenarios":"POST a training start/continue request whose s3_config has use_iam_role unset/false and either access_key_id or secret_access_key missing, None, or empty string, e.g. {\"s3_config\": {\"accessKey\": \"AKIA...\"}} with no secret.","commonSituations":"Storing the access key in an env var that is unset in CI so the field serializes as None; toggling from IAM-role deployment (EKS/k8s) to local development and forgetting to add keys; secret-manager lookups that return empty strings on permission errors; field-name mismatch (access_key_id vs alias accessKey) making one field silently missing.","solutions":["Supply both access_key_id and secret_access_key in s3_config.","Or set use_iam_role=true when running on an instance/cluster with an attached IAM role.","Verify env-var/secret-manager lookups fail loudly rather than yielding empty strings that get serialized into the request.","Check that the client serializes the camelCase aliases (e.g. useIamRole) correctly so the fields actually reach the server."],"exampleFix":"// before\ns3: { access_key_id: process.env.S3_KEY ?? \"\" }\n// after\ns3: {\n  access_key_id: process.env.S3_KEY!,\n  secret_access_key: process.env.S3_SECRET!,\n}\n// or\ns3: { use_iam_role: true }","handlingStrategy":"validation","validationCode":"def s3_credentials_complete(cfg: dict) -> bool:\n    if cfg.get(\"use_iam_role\") or cfg.get(\"useIamRole\"):\n        return True\n    return bool(cfg.get(\"access_key_id\")) and bool(cfg.get(\"secret_access_key\"))","typeGuard":"function s3ConfigOk(cfg: { use_iam_role?: boolean; access_key_id?: string; secret_access_key?: string }): boolean {\n  return Boolean(cfg.use_iam_role) || (Boolean(cfg.access_key_id) && Boolean(cfg.secret_access_key));\n}","tryCatchPattern":null,"preventionTips":["Fail startup/config load loudly when S3 env vars are missing instead of serializing empty strings","Prefer use_iam_role on cloud deployments so no keys travel in requests","Never log the secret_access_key value while debugging this error"],"tags":["pydantic","validation","s3","credentials","aws","training"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}