Trim API key when submitting requests to LLM providers (#37082)

This prevents the common footgun of copy/pasting an API key
starting/ending with extra newlines, which would lead to a "bad request"
error.

Closes #37038 

Release Notes:

- agent: Support pasting language model API keys that contain newlines.
This commit is contained in:
Antonio Scandurra
2025-08-28 12:00:44 +00:00
committed by GitHub
parent 4981c33bf3
commit 39d86eeb7f
6 changed files with 8 additions and 7 deletions
+2 -2
View File
@@ -373,7 +373,7 @@ pub async fn complete(
.uri(uri)
.header("Anthropic-Version", "2023-06-01")
.header("Anthropic-Beta", beta_headers)
.header("X-Api-Key", api_key)
.header("X-Api-Key", api_key.trim())
.header("Content-Type", "application/json");
let serialized_request =
@@ -526,7 +526,7 @@ pub async fn stream_completion_with_rate_limit_info(
.uri(uri)
.header("Anthropic-Version", "2023-06-01")
.header("Anthropic-Beta", beta_headers)
.header("X-Api-Key", api_key)
.header("X-Api-Key", api_key.trim())
.header("Content-Type", "application/json");
let serialized_request =
serde_json::to_string(&request).map_err(AnthropicError::SerializeRequest)?;
+1 -1
View File
@@ -268,7 +268,7 @@ pub async fn stream_completion(
.method(Method::POST)
.uri(uri)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key));
.header("Authorization", format!("Bearer {}", api_key.trim()));
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
let mut response = client.send(request).await?;
+1
View File
@@ -13,6 +13,7 @@ pub async fn stream_generate_content(
api_key: &str,
mut request: GenerateContentRequest,
) -> Result<BoxStream<'static, Result<GenerateContentResponse>>> {
let api_key = api_key.trim();
validate_generate_content_request(&request)?;
// The `model` field is emptied as it is provided as a path parameter.
+1 -1
View File
@@ -482,7 +482,7 @@ pub async fn stream_completion(
.method(Method::POST)
.uri(uri)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key));
.header("Authorization", format!("Bearer {}", api_key.trim()));
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
let mut response = client.send(request).await?;
+2 -2
View File
@@ -461,7 +461,7 @@ pub async fn stream_completion(
.method(Method::POST)
.uri(uri)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key));
.header("Authorization", format!("Bearer {}", api_key.trim()));
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
let mut response = client.send(request).await?;
@@ -565,7 +565,7 @@ pub fn embed<'a>(
.method(Method::POST)
.uri(uri)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.header("Authorization", format!("Bearer {}", api_key.trim()))
.body(body)
.map(|request| client.send(request));
+1 -1
View File
@@ -424,7 +424,7 @@ pub async fn complete(
.method(Method::POST)
.uri(uri)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.header("Authorization", format!("Bearer {}", api_key.trim()))
.header("HTTP-Referer", "https://zed.dev")
.header("X-Title", "Zed Editor");