nikivdev/code · error

unsupported OTP URI scheme: {}

Error message

unsupported OTP URI scheme: {}

What it means

compute_totp accepts either a bare base32 secret (fed to compute_totp_from_secret with defaults) or an otpauth:// URI. If the URI parses but its scheme is not otpauth (e.g. https:// or http://), the function bails because TOTP parameters cannot be extracted from it.

Source

Thrown at src/otp.rs:216

        .first()
        .ok_or_else(|| anyhow::anyhow!("no TOTP field found in item '{}'", item.title))?;

    let value = field
        .value
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("TOTP field in '{}' has no value", item.title))?;

    Ok(value.clone())
}

fn compute_totp(uri: &str) -> Result<String> {
    if !uri.starts_with("otpauth://") {
        return compute_totp_from_secret(uri, 30, 6, "SHA1");
    }

    let url = Url::parse(uri).context("failed to parse otpauth URI")?;
    if url.scheme() != "otpauth" {
        bail!("unsupported OTP URI scheme: {}", url.scheme());
    }

    let mut secret: Option<String> = None;
    let mut digits: u32 = 6;
    let mut period: u64 = 30;
    let mut algorithm = "SHA1".to_string();

    for (key, value) in url.query_pairs() {
        match key.as_ref() {
            "secret" => secret = Some(value.to_string()),
            "digits" => digits = value.parse::<u32>().unwrap_or(6),
            "period" => period = value.parse::<u64>().unwrap_or(30),
            "algorithm" => algorithm = value.to_string(),
            _ => {}
        }
    }

    let secret = secret.ok_or_else(|| anyhow::anyhow!("otpauth URI missing secret"))?;

View on GitHub (pinned to a747e741ae)

Solutions

  1. Open the 1Password item and replace the field's value with the real otpauth://totp/... URI or the base32 secret.
  2. If the field holds a plain base32 secret, store just the secret (no scheme) — it takes the bare-secret path.
  3. Re-run the command after fixing the stored value.

Example fix

// before (item OTP field)
https://example.com/setup

// after
otpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXP&issuer=Example
Defensive patterns

Strategy: validation

Validate before calling

fn is_totp_value(v: &str) -> bool {
    v.starts_with("otpauth://") || !v.contains("://")
}
if !is_totp_value(otp_field) {
    eprintln!("OTP field is neither otpauth:// URI nor bare secret");
}

Type guard

fn is_otpauth_uri(uri: &str) -> bool {
    uri.starts_with("otpauth://")
}

Prevention

When it happens

Trigger: The item's OTP field in 1Password contains a URL whose scheme is not otpauth:// — for example a stored https:// login link was pasted into the TOTP field.

Common situations: Misconfigured 1Password item where someone saved a website URL instead of the TOTP setup key; provisioning script writing the wrong field; provider giving an otpauth-migration:// blob URI.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/de475b2db7eb9838. Report an issue: GitHub.