{"record":{"id":"d4473b0a6452dc55","repo":"neondatabase/neon","slug":"path-is-neither-a-directory-or-a-file","errorCode":null,"errorMessage":"path is neither a directory or a file","messagePattern":"path is neither a directory or a file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/utils/src/auth.rs","lineNumber":168,"sourceCode":"    pub fn from_key_path(key_path: &Utf8Path) -> Result<Self> {\n        let metadata = key_path.metadata()?;\n        let decoding_keys = if metadata.is_dir() {\n            let mut keys = Vec::new();\n            for entry in fs::read_dir(key_path)? {\n                let path = entry?.path();\n                if !path.is_file() {\n                    // Ignore directories (don't recurse)\n                    continue;\n                }\n                let public_key = fs::read(path)?;\n                keys.push(DecodingKey::from_ed_pem(&public_key)?);\n            }\n            keys\n        } else if metadata.is_file() {\n            let public_key = fs::read(key_path)?;\n            vec![DecodingKey::from_ed_pem(&public_key)?]\n        } else {\n            anyhow::bail!(\"path is neither a directory or a file\")\n        };\n        if decoding_keys.is_empty() {\n            anyhow::bail!(\n                \"Configured for JWT auth with zero decoding keys. All JWT gated requests would be rejected.\"\n            );\n        }\n        Ok(Self::new(decoding_keys))\n    }\n\n    pub fn from_key(key: String) -> Result<Self> {\n        Ok(Self::new(vec![DecodingKey::from_ed_pem(key.as_bytes())?]))\n    }\n\n    /// Attempt to decode the token with the internal decoding keys.\n    ///\n    /// The function tries the stored decoding keys in succession,\n    /// and returns the first yielding a successful result.\n    /// If there is no working decoding key, it returns the last error.","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/utils/src/auth.rs#L150-L186","documentation":"JwtAuth::from_key_path stats the configured path; if it exists but is neither a regular file nor a directory (character device, FIFO, socket, block device), it bails with this message. Ed25519 decoding keys can only be loaded from a single PEM file or a directory of PEM files.","triggerScenarios":"Configuring the JWT public key path (e.g. a safekeeper/pageserver auth config pointing at --public-key-path) with a special file such as /dev/null, a unix socket, or a named pipe.","commonSituations":"Using /dev/null to 'disable' auth in scripts; config templating resolving to a device node; Docker bind-mounting a socket over the key path.","solutions":["Point the config at a real Ed25519 public key PEM file or a directory of .pem files","Generate a keypair if needed: openssl genpkey -algorithm ed25519, then publish the public part with openssl pkey -pubout","Re-check the resolved path for typos or incomplete template expansion"],"exampleFix":"# before\n--public-key-path=/dev/null\n# after\nopenssl pkey -in ed25519.pem -pubout -out /etc/neon/public.pem\n--public-key-path=/etc/neon/public.pem","handlingStrategy":"validation","validationCode":"fn is_loadable_key_path(p: &camino::Utf8Path) -> bool {\n    match p.metadata() {\n        Ok(m) => m.is_file() || m.is_dir(),\n        Err(_) => false,\n    }\n}\n\n// run before JwtAuth::from_key_path\nanyhow::ensure!(is_loadable_key_path(&key_path), \"key path must be a regular file or directory\");","typeGuard":"fn is_bad_key_path_error(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"neither a directory or a file\")\n}","tryCatchPattern":"match JwtAuth::from_key_path(&key_path) {\n    Err(e) if e.to_string().contains(\"neither a directory or a file\") => {\n        eprintln!(\"auth key path {key_path} is not a regular file or directory\");\n        std::process::exit(1);\n    }\n    other => other?,\n}","preventionTips":["Validate the key path type during config load, before startup","Never substitute device nodes (/dev/null) for key files","Lint configs in CI with existence and file-type checks"],"tags":["auth","jwt","rust","config","filesystem"],"backgroundTag":"invalid-config-path","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}