{"record":{"id":"95f7b4c55432129b","repo":"cloudflare/cloudflared","slug":"an-api-url-was-not-provided-for-the-cloudflare-api","errorCode":null,"errorMessage":"An api-url was not provided for the Cloudflare API client","messagePattern":"An api-url was not provided for the Cloudflare API client","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/credentials.go","lineNumber":49,"sourceCode":"\treturn c.cert.ZoneID\n}\n\nfunc (c User) APIToken() string {\n\treturn c.cert.APIToken\n}\n\nfunc (c User) CertPath() string {\n\treturn c.certPath\n}\n\nfunc (c User) IsFEDEndpoint() bool {\n\treturn c.cert.Endpoint == FedEndpoint\n}\n\n// Client uses the user credentials to create a Cloudflare API client\nfunc (c *User) Client(apiURL string, userAgent string, log *zerolog.Logger) (cfapi.Client, error) {\n\tif apiURL == \"\" {\n\t\treturn nil, errors.New(\"An api-url was not provided for the Cloudflare API client\")\n\t}\n\tclient, err := cfapi.NewRESTClient(\n\t\tapiURL,\n\t\tc.cert.AccountID,\n\t\tc.cert.ZoneID,\n\t\tc.cert.APIToken,\n\t\tuserAgent,\n\t\tlog,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn client, nil\n}\n\n// Read will load and read the origin cert.pem to load the user credentials\nfunc Read(originCertPath string, log *zerolog.Logger) (*User, error) {\n\toriginCertLog := log.With().","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/credentials/credentials.go#L31-L67","documentation":"credentials.User.Client builds a Cloudflare API client (cloudflare-go cfapi) from the user's tunnel credentials. Because the API endpoint determines where certificate/zone/account calls go, an empty apiURL is rejected up front with this error before any client is constructed.","triggerScenarios":"Calling User.Client with apiURL == \"\" — e.g. the api-url value from flags/config was never set or resolved before constructing the client (as exercised by TestCredentialsClient).","commonSituations":"Custom setups that forgot to pass --api-url; code paths assuming the default Cloudflare API endpoint without supplying it; credentials loaded but the API URL config field left blank.","solutions":["Pass an explicit apiURL, e.g. https://api.cloudflare.com/client/v4, to User.Client","Check that the --api-url flag or its config-file equivalent is actually set before creating the client","Default the value in your code: if apiURL == \"\" use the standard Cloudflare API base URL"],"exampleFix":"// before\napiClient, err := user.Client(\"\", userAgent, log)\n// after\nif apiURL == \"\" {\n    apiURL = \"https://api.cloudflare.com/client/v4\"\n}\napiClient, err := user.Client(apiURL, userAgent, log)","handlingStrategy":"validation","validationCode":"if apiURL == \"\" {\n    return errors.New(\"api-url must be set (e.g. https://api.cloudflare.com/client/v4) before creating the credentials client\")\n}","typeGuard":"func apiURLProvided(apiURL string) bool {\n    u, err := url.Parse(apiURL)\n    return err == nil && u.Scheme != \"\" && u.Host != \"\"\n}","tryCatchPattern":"client, err := user.Client(apiURL, userAgent, log)\nif err != nil && strings.Contains(err.Error(), \"api-url was not provided\") {\n    apiURL = \"https://api.cloudflare.com/client/v4\"\n    client, err = user.Client(apiURL, userAgent, log)\n}","preventionTips":["Default apiURL to https://api.cloudflare.com/client/v4 when unset","Wire --api-url through flags/config consistently in your tooling","Validate the API URL (scheme+host) at startup, before client construction"],"tags":["config","api","missing-value"],"backgroundTag":"missing-required-config","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}