{"record":{"id":"c823380b7f4b42c2","repo":"affaan-m/ECC","slug":"memory-connector-name-path-is-not-a-directory","errorCode":null,"errorMessage":"memory connector {name} path is not a directory: {}","messagePattern":"memory connector (.+?) path is not a directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/main.rs","lineNumber":3126,"sourceCode":"        limit,\n    )?;\n    if stats.records_read < limit {\n        db.upsert_connector_source_checkpoint(name, &source_path, &signature)?;\n    }\n    Ok(stats)\n}\n\nfn sync_jsonl_directory_memory_connector(\n    db: &session::store::StateStore,\n    name: &str,\n    settings: &config::MemoryConnectorJsonlDirectoryConfig,\n    limit: usize,\n) -> Result<GraphConnectorSyncStats> {\n    if settings.path.as_os_str().is_empty() {\n        anyhow::bail!(\"memory connector {name} has no path configured\");\n    }\n    if !settings.path.is_dir() {\n        anyhow::bail!(\n            \"memory connector {name} path is not a directory: {}\",\n            settings.path.display()\n        );\n    }\n\n    let paths = collect_jsonl_paths(&settings.path, settings.recurse)?;\n    let default_session_id = settings\n        .session_id\n        .as_deref()\n        .map(|value| resolve_session_id(db, value))\n        .transpose()?;\n\n    let mut stats = GraphConnectorSyncStats {\n        connector_name: name.to_string(),\n        ..Default::default()\n    };\n\n    let mut remaining = limit;","sourceCodeStart":3108,"sourceCodeEnd":3144,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/main.rs#L3108-L3144","documentation":"After confirming the directory connector's path is configured, the sync function checks `Path::is_dir` and bails if the path exists but is not a directory (e.g. a regular file). Directory connectors expect a directory to walk (optionally recursively via `recurse`) for .jsonl files.","triggerScenarios":"Configuring a jsonl_directory connector whose `path` points at a regular file, a symlink to a file, or a special file instead of a directory.","commonSituations":"Copy-pasting a file path into a directory-type connector config, the target path being replaced by a file after config was written, or a misunderstanding between the file and directory connector variants.","solutions":["Point the directory connector's path at an actual directory containing .jsonl files.","Use the jsonl_file connector variant instead if a single file was intended.","Create the directory if it does not exist yet, then rerun the sync."],"exampleFix":"// before\n[[memory_connectors.jsonl_directory]]\nname = \"sessions\"\npath = \"/home/user/.ecc/sessions.jsonl\"  # wrong: file, not dir\n// after\n[[memory_connectors.jsonl_directory]]\nname = \"sessions\"\npath = \"/home/user/.ecc/sessions\"  # directory","handlingStrategy":"validation","validationCode":"anyhow::ensure!(\n    settings.path.is_dir(),\n    \"directory connector '{}' path is not a directory: {}\",\n    name,\n    settings.path.display()\n);","typeGuard":"fn is_directory(p: &std::path::Path) -> bool {\n    p.is_dir()\n}","tryCatchPattern":"match sync_jsonl_directory(db, name, &settings, limit).await {\n    Ok(stats) => stats,\n    Err(e) if e.to_string().contains(\"not a directory\") => {\n        eprintln!(\"'{}' expects a directory path; got {}\", name, settings.path.display());\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Create the target directory before first sync if it may not exist","Use the file connector variant for single-file paths","Validate path kind (file vs dir) matches connector type at startup"],"tags":["config","filesystem","memory-connector"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}