{"record":{"id":"dc92577975b899df","repo":"cloudflare/cloudflared","slug":"the-tunnel-credentials-file-should-be-json-but-yo","errorCode":null,"errorMessage":"The tunnel credentials file should be .json but you gave a .pem. The tunnel credentials file was originally created by `cloudflared tunnel create`. You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel login`.","messagePattern":"The tunnel credentials file should be \\.json but you gave a \\.pem\\. The tunnel credentials file was originally created by `cloudflared tunnel create`\\. You may have accidentally used the filepath to cert\\.pem, which is generated by `cloudflared tunnel login`\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cloudflared/tunnel/subcommand_context.go","lineNumber":116,"sourceCode":"\t\tsc.userCredential = uc\n\t}\n\treturn sc.userCredential, nil\n}\n\nfunc (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (connection.Credentials, error) {\n\tfilePath, err := credFinder.Path()\n\tif err != nil {\n\t\treturn connection.Credentials{}, err\n\t}\n\tbody, err := sc.fs.readFile(filePath)\n\tif err != nil {\n\t\treturn connection.Credentials{}, errors.Wrapf(err, \"couldn't read tunnel credentials from %v\", filePath)\n\t}\n\n\tvar credentials connection.Credentials\n\tif err = json.Unmarshal(body, &credentials); err != nil {\n\t\tif filepath.Ext(filePath) == \".pem\" {\n\t\t\treturn connection.Credentials{}, fmt.Errorf(\"The tunnel credentials file should be .json but you gave a .pem. \" +\n\t\t\t\t\"The tunnel credentials file was originally created by `cloudflared tunnel create`. \" +\n\t\t\t\t\"You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel \" +\n\t\t\t\t\"login`.\")\n\t\t}\n\t\treturn connection.Credentials{}, invalidJSONCredentialError{path: filePath, err: err}\n\t}\n\treturn credentials, nil\n}\n\nfunc (sc *subcommandContext) create(name string, credentialsFilePath string, secret string) (*cfapi.Tunnel, error) {\n\tclient, err := sc.client()\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"couldn't create client to talk to Cloudflare Tunnel backend\")\n\t}\n\n\tvar tunnelSecret []byte\n\tif secret == \"\" {\n\t\ttunnelSecret, err = generateTunnelSecret()","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cmd/cloudflared/tunnel/subcommand_context.go#L98-L134","documentation":"readTunnelCredentials parses the tunnel credentials file as JSON. If json.Unmarshal fails and the file has a .pem extension, cloudflared raises this dedicated error to tell you the wrong file was passed: credentials files (created by `cloudflared tunnel create`) are JSON, whereas cert.pem (created by `cloudflared tunnel login`) is a PEM certificate. The .pem check exists purely to produce this actionable hint instead of a generic invalid-JSON error.","triggerScenarios":"Calling a tunnel command (e.g. `cloudflared tunnel run --credentials-file <path>`, or findCredentials/findID resolving credentials) with the path to cert.pem instead of <tunnel-id>.json.","commonSituations":"Developers pass ~/.cloudflared/cert.pem because it is the only file in ~/.cloudflared after running `cloudflared tunnel login`; shell autocompletion picks cert.pem; a script variables the wrong path in TUNNEL_CREDENTIALS.","solutions":["Run `cloudflared tunnel list` to find your tunnel, then point --credentials-file at <tunnel-id>.json in ~/.cloudflared (or ~/.cloudflared/config.json's credentials-file key).","If no credentials JSON exists (tunnel created on another machine), recreate the tunnel with `cloudflared tunnel create <name>` to generate one.","If you actually need to authenticate cloudflared itself, run `cloudflared tunnel login` to produce cert.pem — but never pass cert.pem as credentials-file."],"exampleFix":"// before\ncloudflared tunnel run --credentials-file ~/.cloudflared/cert.pem my-tunnel\n// after\ncloudflared tunnel run --credentials-file ~/.cloudflared/<tunnel-uuid>.json my-tunnel","handlingStrategy":"validation","validationCode":"path := \"~/.cloudflared/cert.pem\" // whatever you'd pass\nif filepath.Ext(path) == \".pem\" {\n    return fmt.Errorf(\"refusing to pass %s as credentials-file; expected a JSON file like <tunnel-id>.json\", path)\n}\nif _, err := os.Stat(path); err != nil {\n    return err\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass <tunnel-id>.json (from `cloudflared tunnel create`) as --credentials-file, never cert.pem.","Remember cert.pem = login credentials; <id>.json = tunnel credentials — keep them in separate variables in scripts.","Validate the file extension and that it starts with '{' before invoking cloudflared."],"tags":["cli","config","wrong-file-type","json"],"backgroundTag":"file-not-found","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"}