{"record":{"id":"b07eb34009336970","repo":"rustfs/rustfs","slug":"source-credentials-field-0-must-not-be-empty","errorCode":null,"errorMessage":"source credentials field {0} must not be empty","messagePattern":"source credentials field (.+?) must not be empty","errorType":"validation","errorClass":"OnDemandMigrationConfigError","httpStatus":null,"severity":"error","filePath":"rustfs/src/on_demand_migration/config.rs","lineNumber":470,"sourceCode":"#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]\npub enum OnDemandMigrationConfigError {\n    #[error(\"on-demand migration config version {0} is not supported; expected {ON_DEMAND_MIGRATION_CONFIG_VERSION}\")]\n    UnsupportedVersion(u32),\n    #[error(\"on-demand migration config is not valid JSON: {0}\")]\n    Malformed(String),\n    #[error(\"source endpoint is required for provider {0}\")]\n    MissingEndpoint(Provider),\n    /// Carries only the reason: the endpoint string is operator input that\n    /// may embed credentials, so it is never echoed into an error.\n    #[error(\"source endpoint is invalid: {0}\")]\n    InvalidEndpoint(&'static str),\n    #[error(\"source region must not be empty\")]\n    EmptyRegion,\n    #[error(\"source region \\\"auto\\\" is not supported for provider {0}\")]\n    AutoRegionUnsupported(Provider),\n    #[error(\"source bucket is invalid: {0}\")]\n    InvalidBucket(&'static str),\n    #[error(\"source credentials field {0} must not be empty\")]\n    EmptyCredential(&'static str),\n    #[error(\"source.{0} is required for provider {1}\")]\n    MissingProviderBlock(&'static str, Provider),\n    #[error(\"source.{0} is not valid for provider {1}\")]\n    UnexpectedProviderBlock(&'static str, Provider),\n    /// Carries only the reason: the block holds account keys, SAS tokens and\n    /// service-account JSON, so no value of it is ever echoed.\n    #[error(\"source.{0} is invalid: {1}\")]\n    InvalidProviderBlock(&'static str, &'static str),\n    #[error(\"source tls.ca_cert_pem is not a PEM certificate\")]\n    InvalidCaCert,\n    #[error(\"filter.{0} must be null or a non-empty string\")]\n    EmptyFilterPrefix(&'static str),\n    #[error(\"policy.{field} = {value} is outside {min}..={max}\")]\n    OutOfRange {\n        field: &'static str,\n        value: u64,\n        min: u64,","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/rustfs/rustfs/blob/5dca076efed96e7b842de07c4c2111035ae7c7a2/rustfs/src/on_demand_migration/config.rs#L452-L488","documentation":"OnDemandMigrationConfigError::EmptyCredential (rustfs/src/on_demand_migration/config.rs:470) is raised by SourceConfig::validate when a `source.credentials` block is present for the on-demand migration source but one of its string fields is empty. The carried `&'static str` names the offending field: `access_key`, `secret_key`, or `session_token`. The library rejects empty credentials at the admin boundary so the migration never starts with a source it cannot authenticate to.","triggerScenarios":"Setting `source.credentials.access_key` or `source.credentials.secret_key` to \"\" in the migration config JSON (config.rs:616-620), or setting `source.credentials.session_token` to Some(\"\") (config.rs:622-623), then saving/validating the on-demand migration config.","commonSituations":"Template or UI placeholders left unfilled; an env var like MIGRATION_ACCESS_KEY resolving to empty and being written verbatim into the JSON; a redacted config (xxx in a secrets-management pipeline) copied back and re-submitted.","solutions":["Populate the field named in the message (access_key, secret_key, or session_token) with the real value, or remove the whole credentials block if the source is public/anonymous.","Check that the environment variable or secret reference backing the field is actually set where the admin config is generated.","Re-submit the corrected config via the admin API so validate() runs again."],"exampleFix":"// before\n\"credentials\": {\"access_key\": \"\", \"secret_key\": \"s3cr3t\"}\n// after\n\"credentials\": {\"access_key\": \"AKIA...\", \"secret_key\": \"s3cr3t\"}","handlingStrategy":"validation","validationCode":"fn creds_ok(c: Option<&SourceCredentials>) -> bool {\n    match c {\n        None => true,\n        Some(c) => !c.access_key.is_empty()\n            && !c.secret_key.is_empty()\n            && c.session_token.as_deref().map_or(true, |t| !t.is_empty()),\n    }\n}\nassert!(creds_ok(config.source.credentials.as_ref()), \"empty credential field\");","typeGuard":"fn non_empty(s: &Option<String>) -> bool { s.as_deref().map_or(true, |v| !v.is_empty()) }","tryCatchPattern":null,"preventionTips":["Resolve secret env vars and fail fast on empty strings before building the config JSON.","Never round-trip redacted configs back into the admin API.","Omit the credentials block entirely for anonymous/public sources instead of writing empty strings."],"tags":["rust","config","credentials","validation"],"backgroundTag":"empty-required-field","analyzedSha":"5dca076efed96e7b842de07c4c2111035ae7c7a2","analyzedAt":"2026-09-06T05:54:05.891Z","contentChangedAt":"2026-09-06T05:54:05.891Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}