unslothai/unsloth · error · ValueError
s3_config requires either use_iam_role=True or both access_k
Error message
s3_config requires either use_iam_role=True or both access_key_id and secret_access_key
What it means
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.
Source
Thrown at studio/backend/models/training.py:75
alias = "accessKeyId",
description = "AWS access key ID (optional if using IAM role)",
)
secret_access_key: Optional[str] = Field(
None,
alias = "secretAccessKey",
description = "AWS secret access key (optional if using IAM role)",
)
use_iam_role: bool = Field(
False,
alias = "useIamRole",
description = "Use IAM role credentials instead of access keys",
)
@model_validator(mode = "after")
def _check_credentials(self) -> "S3Config":
# Require either IAM role auth or a full key pair so credentials are never half-configured.
if not self.use_iam_role and not (self.access_key_id and self.secret_access_key):
raise ValueError(
"s3_config requires either use_iam_role=True or both "
"access_key_id and secret_access_key"
)
return self
def _parse_lr(v: Any) -> float:
"""Parse learning_rate as a positive float strictly below _MAX_LR_VALUE."""
if v is None:
raise ValueError("learning_rate is required")
if isinstance(v, bool):
raise ValueError("learning_rate must be a number, not a bool")
try:
lr = float(v)
except (TypeError, ValueError):
raise ValueError(f"learning_rate must be parseable as float (got {v!r})")
if not (lr > 0.0):
raise ValueError(f"learning_rate must be > 0 (got {lr!r}); typical range is 1e-6 .. 1e-3")View on GitHub (pinned to 203007d190)
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.
Example fix
// before
s3: { access_key_id: process.env.S3_KEY ?? "" }
// after
s3: {
access_key_id: process.env.S3_KEY!,
secret_access_key: process.env.S3_SECRET!,
}
// or
s3: { use_iam_role: true } Defensive patterns
Strategy: validation
Validate before calling
def s3_credentials_complete(cfg: dict) -> bool:
if cfg.get("use_iam_role") or cfg.get("useIamRole"):
return True
return bool(cfg.get("access_key_id")) and bool(cfg.get("secret_access_key")) Type guard
function s3ConfigOk(cfg: { use_iam_role?: boolean; access_key_id?: string; secret_access_key?: string }): boolean {
return Boolean(cfg.use_iam_role) || (Boolean(cfg.access_key_id) && Boolean(cfg.secret_access_key));
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- learning_rate is required
- learning_rate must be a number, not a bool
- learning_rate must be parseable as float (got {v!r})
- learning_rate must be > 0 (got {lr!r}); typical range is 1e-
- learning_rate must be < 1.0 (got {lr!r}); values that large
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/bbb77646a72c0ecc.
Report an issue: GitHub.