{"record":{"id":"d5d2ad7b9c512a06","repo":"nautechsystems/nautilus_trader","slug":"description-endpoint-fragments-are-unsupported","errorCode":null,"errorMessage":"{description} endpoint fragments are unsupported","messagePattern":"(.+?) endpoint fragments are unsupported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/http.rs","lineNumber":926,"sourceCode":"    }\n}\n\n#[cfg(feature = \"hypersync\")]\npub(crate) fn validate_execution_endpoint(\n    endpoint: &str,\n    description: &str,\n) -> anyhow::Result<Url> {\n    let url =\n        Url::parse(endpoint).map_err(|_| anyhow::anyhow!(\"Invalid {description} endpoint\"))?;\n    anyhow::ensure!(\n        matches!(url.scheme(), \"http\" | \"https\"),\n        \"{description} endpoint must use HTTPS or canonical loopback HTTP\"\n    );\n    anyhow::ensure!(\n        url.host().is_some(),\n        \"{description} endpoint host is required\"\n    );\n    anyhow::ensure!(\n        url.fragment().is_none(),\n        \"{description} endpoint fragments are unsupported\"\n    );\n    anyhow::ensure!(\n        url.scheme() == \"https\" || is_canonical_loopback_endpoint(endpoint),\n        \"{description} endpoint must use HTTPS unless its host is a canonical loopback IP literal\"\n    );\n    Ok(url)\n}\n\nfn is_canonical_loopback_endpoint(endpoint: &str) -> bool {\n    let Some((scheme, rest)) = endpoint.split_once(\"://\") else {\n        return false;\n    };\n\n    if !scheme.eq_ignore_ascii_case(\"http\") && !scheme.eq_ignore_ascii_case(\"https\") {\n        return false;\n    }","sourceCodeStart":908,"sourceCodeEnd":944,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/http.rs#L908-L944","documentation":"Thrown by `validate_execution_endpoint` when the endpoint URL contains a fragment (`#...`). Fragments are never sent to servers and have no meaning for JSON-RPC endpoints, so the validator rejects them to keep endpoint canonicalization exact.","triggerScenarios":"Endpoint strings copied from browser address bars or docs that carry a `#fragment` suffix (e.g. `https://node.example.com#readme`, `https://host/#/dashboard`) passed to `new` or `normalize_endpoint`.","commonSituations":"Copy-pasting a provider dashboard URL (with SPA hash routes) instead of the raw RPC endpoint URL; appending `#anchor` notes to config values; secret-in-fragment mistakes.","solutions":["Strip everything from `#` onward in the endpoint string.","Use the provider's documented raw RPC URL, not a dashboard/UI URL.","Sanitize config inputs by trimming fragments before constructing the client."],"exampleFix":"// before\nlet endpoint = \"https://node.example.com#settings\"; // fragment rejected\n// after\nlet endpoint = \"https://node.example.com\";","handlingStrategy":"validation","validationCode":"let cleaned = endpoint.split('#').next().unwrap_or(endpoint);\nlet url = url::Url::parse(cleaned)?;\nanyhow::ensure!(url.fragment().is_none(), \"strip the '#...' fragment from the endpoint\");","typeGuard":"fn fragment_free(s: &str) -> bool {\n    url::Url::parse(s).map(|u| u.fragment().is_none()).unwrap_or(false)\n}","tryCatchPattern":"let client = HttpRpcClient::new(endpoint).map_err(|e| {\n    if e.to_string().contains(\"fragments are unsupported\") {\n        anyhow::anyhow!(\"endpoint '{endpoint}' contains a '#fragment'; copy the raw RPC URL from the provider\")\n    } else { e.into() }\n})?;","preventionTips":["Copy the raw RPC URL from provider docs, never from a dashboard address bar.","Normalize config values with split('#').next() before constructing clients.","Never put secrets or annotations after '#' in endpoint config."],"tags":["url","config","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}