{"record":{"id":"25a836d0e19df205","repo":"langchain-ai/deepagents","slug":"remote-source-must-not-contain-credentials","errorCode":null,"errorMessage":"remote source must not contain credentials","messagePattern":"remote source must not contain credentials","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/configuration/types.py","lineNumber":80,"sourceCode":"        msg = \"remote source is too long\"\n        raise ValueError(msg)\n    if any(char.isspace() or not char.isprintable() for char in source):\n        msg = \"remote source must not contain whitespace or control characters\"\n        raise ValueError(msg)\n    try:\n        parsed = urlsplit(source)\n    except ValueError as exc:\n        msg = \"remote source is not a valid URL\"\n        raise ValueError(msg) from exc\n    if not source.isascii():\n        msg = \"remote source must contain only ASCII URI characters\"\n        raise ValueError(msg)\n    if parsed.scheme.lower() != \"https\" or not parsed.hostname:\n        msg = \"remote source must be an absolute HTTPS URL\"\n        raise ValueError(msg)\n    if parsed.username is not None or parsed.password is not None:\n        msg = \"remote source must not contain credentials\"\n        raise ValueError(msg)\n    if parsed.query or parsed.fragment:\n        msg = \"remote source must not contain a query string or fragment\"\n        raise ValueError(msg)\n    try:\n        port = parsed.port\n    except ValueError as exc:\n        msg = \"remote source has an invalid port\"\n        raise ValueError(msg) from exc\n    host = parsed.hostname.rstrip(\".\")\n    netloc = f\"[{host}]\" if \":\" in host else host\n    if port is not None:\n        netloc = f\"{netloc}:{port}\"\n    return parsed._replace(scheme=\"https\", netloc=netloc).geturl()\n\n\n@dataclass(frozen=True, slots=True)\nclass ProviderStatus:\n    \"\"\"Health and safe diagnostic detail for one provider.\"\"\"","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/configuration/types.py#L62-L98","documentation":"Raised by `_validate_remote_source_url` when the parsed HTTPS URL embeds userinfo credentials (a username or password, e.g. 'https://user:pass@example.com/...'). The library forbids credentials in remote source URLs so secrets do not leak into logs, caches, or serialized configuration; authentication must happen out of band.","triggerScenarios":"Constructing the remote-source dataclass with a URL containing '@' userinfo such as 'https://token@github.com/org/repo/config.toml' or 'https://user:pass@example.com/x.toml' — parsed.username or parsed.password is not None.","commonSituations":"Copying an authenticated git/clone URL (personal access token in the URL) into a remote_source field; sharing a colleague's bookmarked URL that embeds an API token; older tooling that recommended token-in-URL auth.","solutions":["Remove the username/password from the URL (strip everything up to and including '@' before the host)","Move the credential to an environment variable or credential helper consumed by the fetcher, not the URL","If using a git host, use a public raw HTTPS URL for the config file instead of a clone URL","Rotate the credential if it was already committed to a config file — it may have been captured in logs"],"exampleFix":"// before\nRemoteSource(source=\"https://ghp_abc123@raw.githubusercontent.com/org/repo/main/config.toml\")\n// after\nRemoteSource(source=\"https://raw.githubusercontent.com/org/repo/main/config.toml\")","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef has_url_credentials(source: str) -> bool:\n    parsed = urlparse(source)\n    return parsed.username is not None or parsed.password is not None\n\nassert not has_url_credentials(src), \"strip credentials from remote_source\"","typeGuard":"def is_credential_free_url(value: str) -> bool:\n    parsed = urlparse(value)\n    return parsed.username is None and parsed.password is None","tryCatchPattern":"try:\n    RemoteSource(source=src)\nexcept ValueError as exc:\n    if \"credentials\" in str(exc):\n        src = re.sub(r\"^[a-z][a-z0-9+.-]*://[^/@]*@\", lambda m: m.group(0).split('://')[0] + '://', src)\n    raise ConfigError(\"remove credentials from remote_source; use env vars\") from exc","preventionTips":["Never paste clone URLs with embedded tokens into config","Store credentials in env vars or a credential helper","Scan committed config for '@' inside URLs and rotate any leaked tokens"],"tags":["validation","security","url","credentials"],"backgroundTag":"credentials-in-url","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}