{"record":{"id":"c8b27a2f86a376bf","repo":"Hmbown/CodeWhale","slug":"config-file-exceeds-the-1-mib-limit","errorCode":null,"errorMessage":"config file {} exceeds the 1 MiB limit","messagePattern":"config file (.+?) exceeds the 1 MiB limit","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":6880,"sourceCode":"    read_string_no_follow(&path)\n        .with_context(|| format!(\"failed to read {label} at {}\", path.display()))\n}\n\n/// Maximum bytes read from a config file. Configs are kilobytes; anything\n/// larger is not a config file.\nconst MAX_CONFIG_FILE_BYTES: u64 = 1024 * 1024;\n\n#[cfg(unix)]\nfn read_string_no_follow(path: &Path) -> std::io::Result<String> {\n    let file = fs::OpenOptions::new()\n        .read(true)\n        .custom_flags(libc::O_NOFOLLOW)\n        .open(path)?;\n    let mut raw = String::new();\n    file.take(MAX_CONFIG_FILE_BYTES + 1)\n        .read_to_string(&mut raw)?;\n    if raw.len() as u64 > MAX_CONFIG_FILE_BYTES {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            format!(\"config file {} exceeds the 1 MiB limit\", path.display()),\n        ));\n    }\n    Ok(raw)\n}\n\n#[cfg(not(unix))]\nfn read_string_no_follow(path: &Path) -> std::io::Result<String> {\n    let file = fs::File::open(path)?;\n    let mut raw = String::new();\n    file.take(MAX_CONFIG_FILE_BYTES + 1)\n        .read_to_string(&mut raw)?;\n    if raw.len() as u64 > MAX_CONFIG_FILE_BYTES {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            format!(\"config file {} exceeds the 1 MiB limit\", path.display()),\n        ));","sourceCodeStart":6862,"sourceCodeEnd":6898,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/lib.rs#L6862-L6898","documentation":"The config loader reads config files with a hard cap of MAX_CONFIG_FILE_BYTES (1 MiB), using read(2) with O_NOFOLLOW and take(limit+1) so oversized files are detected without reading them fully into memory unbounded. If the file's byte length exceeds 1 MiB it returns an InvalidData io::Error naming the path. This is a safety guard against absurd/corrupt config files and symlink attacks.","triggerScenarios":"Loading a config file (via the no-follow hardened reader path) whose size on disk is greater than 1 MiB — the read is capped at MAX_CONFIG_FILE_BYTES + 1 bytes and the length check fires.","commonSituations":"A config generator or tool concatenated credentials/prompts into the config until it grew past 1 MiB; a symlink or bind-mount pointed the config path at a huge file (the O_NOFOLLOW flag catches plain symlinks); accidental binary/log file placed at the config path.","solutions":["Inspect the file at the reported path (`ls -lh`, `wc -c`) and trim it under 1 MiB — remove duplicated or commented-out sections","Regenerate the config from a known-good template instead of hand-editing the bloated one","Check whether scripts/CI write into the config path and bound their output","Verify the path is a regular file, not a symlink to something huge"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import os\npath = \"~/.codewhale/config.toml\"\nif os.path.getsize(os.path.expanduser(path)) > 1024*1024:\n    raise SystemExit(f\"{path} exceeds 1 MiB; trim before loading\")","typeGuard":null,"tryCatchPattern":"match std::fs::read(path) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData =>\n        eprintln!(\"config too large (>1MiB): regenerate it\"),\n    other => other,\n}","preventionTips":["Keep machine-generated data out of the config file; reference external files instead","Lint configs in CI for size before deployment","Alert if the config path grows beyond a few hundred KiB","Ensure the path resolves to a regular file, not a symlink"],"tags":["config","file-size","validation"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}