{"record":{"id":"96b82dc0ac0621d5","repo":"astrid-runtime/astrid","slug":"invalidinput-96b82d","errorCode":"InvalidInput","errorMessage":"Windows file name is too long","messagePattern":"Windows file name is too long","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/astrid-core/src/platform_fs/windows/io.rs","lineNumber":511,"sourceCode":"    guard.verify_contract(boundary_contract)\n}\n\nfn rename_guarded_file(\n    guard: &TrustedPathGuard,\n    source: &Path,\n    destination: &Path,\n    replace: bool,\n) -> io::Result<()> {\n    let source_name = guarded_child_name(guard, source)?;\n    let destination_name = guarded_child_name(guard, destination)?;\n    let source = open_guarded_child(guard, source_name, DELETE | FILE_READ_ATTRIBUTES)?;\n    let destination_wide = destination_name.encode_wide().collect::<Vec<_>>();\n    let name_bytes = destination_wide\n        .len()\n        .checked_mul(size_of::<u16>())\n        .and_then(|length| u32::try_from(length).ok())\n        .ok_or_else(|| {\n            io::Error::new(io::ErrorKind::InvalidInput, \"Windows file name is too long\")\n        })?;\n    let buffer_bytes = size_of::<FILE_RENAME_INFORMATION>()\n        .checked_add(usize::try_from(name_bytes).expect(\"u32 length fits usize\"))\n        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, \"rename buffer overflow\"))?;\n    // `Vec<usize>` supplies native pointer alignment and zero-initializes the\n    // full fixed structure plus the variable-length UTF-16 name bytes required\n    // by `NtSetInformationFile`.\n    let mut buffer = vec![0_usize; buffer_bytes.div_ceil(size_of::<usize>())];\n    let info = buffer.as_mut_ptr().cast::<FILE_RENAME_INFORMATION>();\n    let information_class = if replace {\n        FileRenameInformationEx\n    } else {\n        FileRenameInformation\n    };\n    // SAFETY: the usize buffer is sufficiently aligned and sized for the\n    // variable-length FILE_RENAME_INFORMATION followed by the UTF-16 component.\n    unsafe {\n        if replace {","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs/windows/io.rs#L493-L529","documentation":"rename_guarded_file performs an NT-level rename (NtSetInformationFile with FILE_RENAME_INFORMATION) and must pack the destination file name as UTF-16 into a u32 length field. This error fires when the UTF-16 name length (UTF-16 code units × 2 bytes) cannot be represented as u32 — i.e. the destination path component is absurdly long. It is a defensive pre-flight check before allocating and filling the rename buffer.","triggerScenarios":"Raised in rename_guarded_file (via replace_file_checked / move_guarded_file) when `destination_wide.len() * size_of::<u16>()` overflows u32::try_from. Only reachable with a destination name of more than ~2^31 UTF-16 code units — practically only via corrupted path inputs, unbounded string concatenation, or a bug that passes garbage into `destination`.","commonSituations":"A bug in caller code building destination paths in a loop (e.g. joining the same component repeatedly); deserialized/path-traversal-ish input containing a runaway file name; unit/integration tests passing malformed paths.","solutions":["Audit the code that constructs the destination path — a name this long means the path is being built incorrectly (check for repeated join/format loops).","Validate the destination file name length before calling replace_file_checked/move_guarded_file (keep components under 255 UTF-16 units per Windows limits).","Reject or sanitize untrusted input that feeds the destination file name before invoking the guarded move/replace APIs."],"exampleFix":"// before: blindly passing a possibly runaway name\nmove_guarded_file(&guard, &source, &install_dir.join(&user_supplied_name))?;\n// after: pre-validate the component\nlet name = user_supplied_name;\nif name.chars().count() == 0 || name.chars().count() > 255 {\n    return Err(io::Error::new(io::ErrorKind::InvalidInput, \"invalid file name\"));\n}\nmove_guarded_file(&guard, &source, &install_dir.join(name))?;","handlingStrategy":"validation","validationCode":"// Rust: validate the destination component before any guarded rename/move\nfn valid_component(name: &str) -> io::Result<()> {\n    let units = name.encode_utf16().count();\n    if units == 0 || units > 255 {\n        return Err(io::Error::new(io::ErrorKind::InvalidInput, \"file name component out of range\"));\n    }\n    if name.contains(['/', '\\\\', ':', '*', '?', '\"', '<', '>', '|']) {\n        return Err(io::Error::new(io::ErrorKind::InvalidInput, \"illegal characters in file name\"));\n    }\n    Ok(())\n}","typeGuard":"fn is_valid_windows_component(name: &str) -> bool {\n    let units = name.encode_utf16().count();\n    units > 0 && units <= 255 && !name.contains(['/', '\\\\', ':', '*', '?', '\"', '<', '>', '|'])\n}","tryCatchPattern":"// Rust\nmatch replace_file_checked(&guard, &live, &replacement) {\n    Ok(()) => finish(),\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput => {\n        eprintln!(\"bad destination path for rename: {e}\");\n        // do not retry: fix the path construction\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep file name components at or under 255 UTF-16 units.","Never build destination names with unbounded loops or raw user input.","Sanitize/whitelist characters in file names derived from external data.","Unit-test path construction with adversarial long names."],"tags":["windows","filesystem","path-length","rename","ntapi"],"backgroundTag":"value-out-of-range","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}