{"record":{"id":"de475b2db7eb9838","repo":"nikivdev/code","slug":"unsupported-otp-uri-scheme","errorCode":null,"errorMessage":"unsupported OTP URI scheme: {}","messagePattern":"unsupported OTP URI scheme: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/otp.rs","lineNumber":216,"sourceCode":"        .first()\n        .ok_or_else(|| anyhow::anyhow!(\"no TOTP field found in item '{}'\", item.title))?;\n\n    let value = field\n        .value\n        .as_ref()\n        .ok_or_else(|| anyhow::anyhow!(\"TOTP field in '{}' has no value\", item.title))?;\n\n    Ok(value.clone())\n}\n\nfn compute_totp(uri: &str) -> Result<String> {\n    if !uri.starts_with(\"otpauth://\") {\n        return compute_totp_from_secret(uri, 30, 6, \"SHA1\");\n    }\n\n    let url = Url::parse(uri).context(\"failed to parse otpauth URI\")?;\n    if url.scheme() != \"otpauth\" {\n        bail!(\"unsupported OTP URI scheme: {}\", url.scheme());\n    }\n\n    let mut secret: Option<String> = None;\n    let mut digits: u32 = 6;\n    let mut period: u64 = 30;\n    let mut algorithm = \"SHA1\".to_string();\n\n    for (key, value) in url.query_pairs() {\n        match key.as_ref() {\n            \"secret\" => secret = Some(value.to_string()),\n            \"digits\" => digits = value.parse::<u32>().unwrap_or(6),\n            \"period\" => period = value.parse::<u64>().unwrap_or(30),\n            \"algorithm\" => algorithm = value.to_string(),\n            _ => {}\n        }\n    }\n\n    let secret = secret.ok_or_else(|| anyhow::anyhow!(\"otpauth URI missing secret\"))?;","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/otp.rs#L198-L234","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the 1Password item and replace the field's value with the real otpauth://totp/... URI or the base32 secret.","If the field holds a plain base32 secret, store just the secret (no scheme) — it takes the bare-secret path.","Re-run the command after fixing the stored value."],"exampleFix":"// before (item OTP field)\nhttps://example.com/setup\n\n// after\notpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXP&issuer=Example","handlingStrategy":"validation","validationCode":"fn is_totp_value(v: &str) -> bool {\n    v.starts_with(\"otpauth://\") || !v.contains(\"://\")\n}\nif !is_totp_value(otp_field) {\n    eprintln!(\"OTP field is neither otpauth:// URI nor bare secret\");\n}","typeGuard":"fn is_otpauth_uri(uri: &str) -> bool {\n    uri.starts_with(\"otpauth://\")\n}","tryCatchPattern":null,"preventionTips":["Store either a bare base32 secret or an otpauth://totp/... URI in the item's OTP field — never a website URL.","Validate provisioning scripts write the otpauth URI, not the issuer's setup page link.","If your provider emits otpauth-migration:// blobs, convert them to a single otpauth://totp URI first."],"tags":["totp","otp","uri","validation"],"backgroundTag":"invalid-uri-scheme","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}