{"record":{"id":"3b6391878508b149","repo":"nikivdev/code","slug":"relative-path-cannot-be-empty","errorCode":null,"errorMessage":"Relative path cannot be empty.","messagePattern":"Relative path cannot be empty\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/code.rs","lineNumber":804,"sourceCode":"        }\n    }\n    if opts.dry_run {\n        println!(\"Dry run only; no files were changed.\");\n    }\n\n    Ok(())\n}\n\nfn normalize_path(path: &str) -> Result<PathBuf> {\n    let expanded = config::expand_path(path);\n    let canonical = expanded.canonicalize().unwrap_or(expanded);\n    Ok(canonical)\n}\n\nfn normalize_relative_path(path: &str) -> Result<PathBuf> {\n    let trimmed = path.trim();\n    if trimmed.is_empty() {\n        bail!(\"Relative path cannot be empty.\");\n    }\n    let rel = PathBuf::from(trimmed);\n    if rel.is_absolute() {\n        bail!(\"Relative path must not be absolute.\");\n    }\n    for component in rel.components() {\n        if matches!(component, std::path::Component::ParentDir) {\n            bail!(\"Relative path must not contain '..'.\");\n        }\n    }\n    Ok(rel)\n}\n\nfn move_dir(from: &Path, to: &Path) -> Result<()> {\n    match fs::rename(from, to) {\n        Ok(()) => Ok(()),\n        Err(err) => {\n            if is_cross_device(&err) {","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/code.rs#L786-L822","documentation":"normalize_relative_path sanitizes a user-supplied relative subdirectory name before it is joined onto a project root (used by new_project and migrate_project). After trimming whitespace, an empty string has no meaningful directory component, so the function bails rather than silently resolving to the root itself. This prevents accidentally creating/migrating into the root when an argument was forgotten.","triggerScenarios":"Calling new_project or migrate_project with a relative-path argument that is empty or only whitespace (\"\", \"   \", \"\\t\") — e.g. an unset shell variable or an empty CLI flag value.","commonSituations":"`--path \"$NAME\"` where $NAME is unset/empty; forms or config files with a blank field; scripts stripping a prefix down to an empty string; users pressing Enter at an interactive prompt.","solutions":["Pass a non-empty relative directory name, e.g. `\"my-project\"`.","Validate the argument in your shell: `[ -n \"$NAME\" ] || { echo 'path required'; exit 1; }`.","Check that the value is not only whitespace — trim it before calling if your input may contain spaces.","If the project should live at the root, don't call with an empty path; use the root-targeting API/flag explicitly if one exists."],"exampleFix":"// before\nlet rel = std::env::var(\"PROJECT_SUBDIR\").unwrap_or_default(); // \"\" when unset\n// after\nlet rel = std::env::var(\"PROJECT_SUBDIR\").context(\"PROJECT_SUBDIR must be set\")?;","handlingStrategy":"validation","validationCode":"let rel = input.trim();\nif rel.is_empty() {\n    return Err(\"a non-empty relative project path is required\".into());\n}","typeGuard":"fn is_non_empty(s: &str) -> bool { !s.trim().is_empty() }","tryCatchPattern":"match new_project(&rel) {\n    Err(e) if e.to_string().contains(\"Relative path cannot be empty\") => {\n        eprintln!(\"Provide a project name/path argument.\");\n    }\n    other => other?,\n}","preventionTips":["Check shell variables are set before interpolation (`${VAR:?msg}`).","Require the argument at the CLI layer with a clear usage message.","Trim user input before passing it through."],"tags":["path-validation","input-validation","cli"],"backgroundTag":"empty-path-argument","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}