Kuberwastaken/claurst · critical
unable to parse api key for http header
Error message
unable to parse api key for http header
What it means
MinimaxProvider::new inserts the API key as an X-Api-Key default header using HeaderValue::from_str(&api_key).expect(...). HTTP header values must contain only visible ASCII (bytes 0x20–0x7E, plus a few others); if the key contains whitespace control chars, newlines, or non-ASCII bytes, from_str fails and the provider panics with this message.
Solutions
- Trim whitespace/newlines from the API key before constructing the provider: api_key.trim().
- Verify the key with `od -c` or similar to detect hidden control characters or non-ASCII bytes.
- Regenerate/copy the key directly from the provider dashboard without transformation (no base64, no wrapping).
- If constructing in your own code, validate with HeaderValue::from_str first and return a proper error instead of panicking.
Example fix
// before
let provider = MinimaxProvider::new(std::env::var("MINIMAX_API_KEY")?);
// after
let key = std::env::var("MINIMAX_API_KEY")?;
let key = key.trim().to_string();
header::HeaderValue::from_str(&key)
.context("MINIMAX_API_KEY contains invalid characters for an HTTP header")?;
let provider = MinimaxProvider::new(key); Defensive patterns
Strategy: validation
Validate before calling
fn valid_header_value(s: &str) -> bool {
!s.is_empty() && s.bytes().all(|b| (0x20..=0x7E).contains(&b) || b == 0x09)
}
// before constructing:
let key = api_key.trim();
if !valid_header_value(key) { return Err(anyhow!("MINIMAX_API_KEY contains characters invalid in an HTTP header")); } Type guard
fn as_header_value(s: &str) -> Option<reqwest::header::HeaderValue> {
reqwest::header::HeaderValue::from_str(s.trim()).ok()
} Try / catch
// this panic cannot be caught in Rust; pre-validate instead
let key = api_key.trim();
match reqwest::header::HeaderValue::from_str(key) {
Ok(_) => MinimaxProvider::new(key.to_string()),
Err(e) => return Err(anyhow!("invalid MINIMAX_API_KEY header value: {e}")),
} Prevention
- Always trim() API keys read from env vars or files.
- Never base64-encode or newline-wrap keys destined for header values.
- Inspect suspicious keys with `od -c` for hidden control characters.
- Copy keys straight from the provider dashboard without intermediate editors.
- Pre-validate with HeaderValue::from_str before constructing the provider.
When it happens
Trigger: Passing an api_key containing non-ASCII or control characters (e.g. a newline from a mis-trimmed env var, a paste with trailing CR, or a UTF-8 multi-byte character) into MinimaxProvider::new.
Common situations: Copying an API key with a trailing newline into an env file; shell quoting adding whitespace; using a base64-encoded or otherwise transformed key that includes padding/newlines; terminal paste artifacts.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- No API key found. Options: - Set ANTHROPIC_API_KEY for…
- Login succeeded but could not obtain a usable credential
- API key creation failed
- Plugin name cannot be empty
- Plugin name ' ' cannot contain spaces. Use kebab-case.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/a5ed613d19207b22.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/api/src/providers/minimax.rs:37
};
use crate::types::{ApiMessage, ApiToolDefinition, CreateMessageRequest, ThinkingConfig};
use super::message_normalization::normalize_anthropic_messages;
pub struct MinimaxProvider {
http_client: Client,
api_key: String,
api_base: String,
service_tier: Option<String>,
id: ProviderId,
}
impl MinimaxProvider {
pub fn new(api_key: String) -> Self {
let api_base = std::env::var("MINIMAX_BASE_URL")
.unwrap_or_else(|_| claurst_core::constants::MINIMAX_ANTHROPIC_API_BASE.to_string());
let mut headers = header::HeaderMap::new();
headers.insert("X-Api-Key", header::HeaderValue::from_str(&api_key).expect("unable to parse api key for http header"));
let http_client = Client::builder()
.default_headers(headers)
.timeout(crate::request_timeout())
.build()
.expect("MinimaxProvider: failed to build HTTP client");
Self {
http_client,
api_key,
api_base,
service_tier: None,
id: ProviderId::new(ProviderId::MINIMAX),
}
}
pub fn with_base_url(mut self, api_base: impl Into<String>) -> Self {
self.api_base = api_base.into();
selfView on GitHub (pinned to b0637c97ec)