neondatabase/neon · error

Endpoint::from_dir_entry failed: '{}' is not a directory

Error message

Endpoint::from_dir_entry failed: '{}' is not a directory

What it means

Endpoint::from_dir_entry is called for each entry under the endpoints root directory when listing/loading endpoints; each entry is expected to be a directory named with the endpoint id and containing endpoint.json. If an entry is a regular file (or symlink to one), loading aborts with this error before any parsing happens.

Source

Thrown at control_plane/src/endpoint.rs:408

pub struct EndpointStartArgs {
    pub auth_token: Option<String>,
    pub endpoint_storage_token: String,
    pub endpoint_storage_addr: String,
    pub safekeepers_generation: Option<SafekeeperGeneration>,
    pub safekeepers: Vec<NodeId>,
    pub pageserver_conninfo: PageserverConnectionInfo,
    pub remote_ext_base_url: Option<String>,
    pub create_test_user: bool,
    pub start_timeout: Duration,
    pub autoprewarm: bool,
    pub offload_lfc_interval_seconds: Option<std::num::NonZeroU64>,
    pub dev: bool,
}

impl Endpoint {
    fn from_dir_entry(entry: std::fs::DirEntry, env: &LocalEnv) -> Result<Endpoint> {
        if !entry.file_type()?.is_dir() {
            anyhow::bail!(
                "Endpoint::from_dir_entry failed: '{}' is not a directory",
                entry.path().display()
            );
        }

        // parse data directory name
        let fname = entry.file_name();
        let endpoint_id = fname.to_str().unwrap().to_string();

        // Read the endpoint.json file
        let conf: EndpointConf =
            serde_json::from_slice(&std::fs::read(entry.path().join("endpoint.json"))?)?;

        debug!("serialized endpoint conf: {:?}", conf);

        Ok(Endpoint {
            pg_address: SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), conf.pg_port),
            external_http_address: SocketAddr::new(

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. List the endpoints directory (`ls -la <neon_dir>/endpoints`) and delete or move any non-directory entries.
  2. Recreate the endpoint properly if a partial create left junk: remove the stray file and run endpoint create again.
  3. Avoid writing anything into the neon_local endpoints root; put scratch files elsewhere.
  4. Filter non-directory entries before calling the listing API if you build tooling on top of it.

Example fix

// before
for entry in std::fs::read_dir(endpoints_dir)? {
    let ep = Endpoint::from_dir_entry(entry?, &env)?; // bails on stray file
}

// after
for entry in std::fs::read_dir(endpoints_dir)? {
    let entry = entry?;
    if !entry.file_type()?.is_dir() {
        continue; // skip stray files instead of failing the whole listing
    }
    let ep = Endpoint::from_dir_entry(entry, &env)?;
}
Defensive patterns

Strategy: validation

Validate before calling

// only pass directory entries to the listing path
for entry in std::fs::read_dir(&endpoints_dir)? {
    let entry = entry?;
    if !entry.file_type()?.is_dir() { continue; }
    let ep = Endpoint::from_dir_entry(entry, &env)?;
}

Type guard

fn is_endpoint_dir(entry: &std::fs::DirEntry) -> bool {
    entry.file_type().map(|t| t.is_dir()).unwrap_or(false)
}

Try / catch

match Endpoint::from_dir_entry(entry, &env) {
    Err(e) if e.to_string().contains("is not a directory") => continue, // skip stray file
    other => other?,
}

Prevention

When it happens

Trigger: Running an operation that enumerates endpoints (`neon_local endpoints list`, env start) when the endpoints directory contains a stray file: a manually created note, an editor backup, .DS_Store, a log file redirected into the wrong place, or a half-written directory replaced by a file.

Common situations: Developers touching the neonLocalPath endpoints dir by hand; tooling writing marker files next to endpoint dirs; a crashed `endpoint create` leaving a file instead of a directory; syncing artifacts into the repo's working dir.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/448c7ca6e6c244f2. Report an issue: GitHub.