zeroclaw-labs/zeroclaw · error
Refusing to transmit sensitive data over non-HTTPS URL: URL
Error message
Refusing to transmit sensitive data over non-HTTPS URL: URL scheme must be https
What it means
ensure_https is the guard run by upload_media, send_media_message, and send_text_markdown before any QQ HTTP call; it rejects every URL that does not start with "https://" because these requests carry the app access token and user media. It exists so a misconfigured or tampered base/media URL can never downgrade credentials to plaintext HTTP. It is a deliberate refusal, not a network failure.
Source
Thrown at crates/zeroclaw-channels/src/qq.rs:72
voice_dedup_parts: Vec<QQVoiceDedupPart>,
}
/// Response from QQ media upload API.
#[derive(Debug, Deserialize)]
struct QQUploadResponse {
file_info: String,
ttl: Option<u64>,
}
/// Cached upload entry to avoid re-uploading the same file within TTL.
struct UploadCacheEntry {
file_info: String,
expires_at: u64,
}
fn ensure_https(url: &str) -> anyhow::Result<()> {
if !url.starts_with("https://") {
anyhow::bail!(
"Refusing to transmit sensitive data over non-HTTPS URL: URL scheme must be https"
);
}
Ok(())
}
/// Check whether a file extension is a natively supported QQ voice format.
fn is_native_voice_ext(ext: &str) -> bool {
matches!(ext.to_ascii_lowercase().as_str(), "wav" | "mp3" | "silk")
}
fn has_supported_transcription_extension(filename: &str) -> bool {
let ext = Path::new(filename)
.extension()
.and_then(|e| e.to_str())
.unwrap_or("")
.to_ascii_lowercase();
View on GitHub (pinned to 88bb9c8533)
Solutions
- Change the offending URL to https:// (real QQ endpoints api.sgroup.qq.com and bots.qq.com are https)
- For local tests, use a TLS-capable mock server or the platform's https test endpoint instead of plain http
- Audit any api-base/media URL override fields in [channels.qq.*] and remove http:// values
Example fix
# before [channels.qq.main] api_base = "http://qq-mock.internal:8080" # -> bail: non-HTTPS URL refused # after [channels.qq.main] api_base = "https://qq-mock.internal:8443"
Defensive patterns
Strategy: validation
Validate before calling
// Before invoking QQ send paths, apply the same rule the library enforces:
fn qq_urls_are_https(urls: &[&str]) -> anyhow::Result<()> {
for u in urls {
if !u.starts_with("https://") {
anyhow::bail!("refusing non-HTTPS QQ URL: {u}");
}
}
Ok(())
}
qq_urls_are_https(&[api_base, media_url])?; Type guard
fn is_https(url: &str) -> bool {
url.starts_with("https://")
}
assert!(is_https("https://api.sgroup.qq.com"));
assert!(!is_https("http://qq-mock.internal:8080")); Try / catch
match ch.send(&msg).await {
Err(e) if e.to_string().contains("non-HTTPS URL") => {
// Deterministic security refusal: fix the URL source (config override / proxy); never downgrade.
}
rest => rest?,
} Prevention
- Never put http:// endpoints in [channels.qq.*] URL fields — the guard exists to protect the access token
- Use https mock servers in integration tests instead of plain-http stubs
- Audit URL-producing overrides after proxy or environment changes
When it happens
Trigger: Any URL reaching the QQ HTTP helpers configured or overridden as http:// — e.g. an api base override for testing, a proxy rewriting URLs, or a media URL from a marker like [IMAGE:http://...] where the value is used as an endpoint rather than a fetch target.
Common situations: Pointing the channel at an http:// mock server in tests (use an https test server instead); corporate proxies that hand back http:// URLs; copy-pasting an internal http endpoint into a field that is used for authenticated API calls.
Related errors
- {field_name} must use https://, got {url}
- Refusing to transmit sensitive data over non-HTTPS URL: URL
- refusing non-HTTPS attachment URL: {url}
- xAI OAuth discovery returned non-HTTPS {label}
- URL userinfo is not allowed
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0a6360b8e47bb498.
Report an issue: GitHub.