gleam-lang/gleam · error
OAuth credentials TOML encoding
Error message
OAuth credentials TOML encoding
What it means
Panic from `toml::to_string(&credentials).expect("OAuth credentials TOML encoding")` in encrypt_and_store_oauth_refresh_token in compiler-cli/src/hex/auth.rs. Serializing the Hex credentials struct to TOML failed — practically only possible if the struct contains types the toml serializer cannot represent (e.g. None-bearing fields where the schema expects strings, or map types TOML can't express). The stored OAuth credentials file therefore cannot be written.
Solutions
- Inspect the credentials struct and ensure all fields are TOML-compatible (strings, plain structs, no nested maps under non-string keys, no unexpected None).
- Replace the expect with proper error propagation so the user sees a message instead of a panic.
- Update the serde attributes (skip_serializing_if = "Option::is_none") on fields that may be absent.
- Pin or upgrade the toml crate deliberately after verifying the struct still serializes; add a round-trip unit test.
Example fix
// before
let toml = toml::to_string(&credentials).expect("OAuth credentials TOML encoding");
// after
let toml = toml::to_string(&credentials)
.map_err(|e| anyhow::anyhow!("Failed to encode OAuth credentials as TOML: {e}"))?; Defensive patterns
Strategy: validation
Validate before calling
// Round-trip check before storing:
if toml::to_string(&credentials).is_err() { eprintln!("credentials not TOML-serializable"); } Type guard
fn toml_serializable<T: serde::Serialize>(v: &T) -> bool { toml::to_string(v).is_ok() } Try / catch
match toml::to_string(&credentials) { Ok(t) => crate::fs::write(&path, &t)?, Err(e) => return Err(anyhow::anyhow!("TOML encoding failed: {e}")) } Prevention
- Keep credentials structs limited to TOML-friendly field types.
- Add round-trip (serialize->deserialize) unit tests for credential storage.
- Annotate optional fields with skip_serializing_if.
When it happens
Trigger: Completing the OAuth device flow (create_and_store_new_credentials_via_oauth) or refreshing stored tokens (read_and_decrypt_and_refresh_stored_tokens) when the credentials struct shape can't be represented in TOML — e.g. after a struct field type change in HexAuthentication's credentials model.
Common situations: A refactor changes a credentials field to a nested map/Option layout the toml crate rejects; upgrading the toml crate introduces stricter serializer rules.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/439ef1968b6d67c2.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-cli/src/hex/auth.rs:139
let encrypted_refresh_token =
encryption::encrypt_with_passphrase(tokens.refresh_token.as_bytes(), &local_password)
.map_err(|error| Error::FailedToEncryptLocalHexApiKey {
detail: error.to_string(),
})?;
let credentials = StoredOAuthCredentials {
hexpm: StoredOAuthRepoCredentials {
api: self.hex_config.api_base.clone(),
repository: self.hex_config.repository_base.clone(),
refresh_token: encrypted_refresh_token,
refresh_token_hash: {
let mut hasher = sha2::Sha256::new();
hasher.update(tokens.refresh_token.as_bytes());
base16::encode_lower(&hasher.finalize())
},
},
};
let toml = toml::to_string(&credentials).expect("OAuth credentials TOML encoding");
crate::fs::write(&path, &toml)?;
Ok(())
}
/// Create a new local password.
///
/// The password must be long enough.
///
/// The old password will be discarded, and the new one will be both
/// returned and stored in `self.local_password`
///
fn ask_for_new_local_password(&mut self) -> Result<()> {
let required_length = 8;
self.local_password = None;
println!(
"Please enter a new unique password, at least {required_length} characters long.
It will be used to locally encrypt your Hex API tokens.
"View on GitHub (pinned to 15b07c7830)