{"tool_call":"file.create","args":{"content":"# How does anyhow::Error::new differ from anyhow::Error::msg for constructing error instances?
Error::new converts any type implementing std::error::Error into an anyhow::Error, preserving the original error as the source chain. Error::msg creates an ad-hoc error from a string without any underlying cause, producing a root error that has no source(). The key difference is that Error::new wraps existing errors while Error::msg creates new leaf errors. Use Error::new when you have a concrete error type that should be propagated, and Error::msg when you need to create an error from a message string without an underlying error cause.
Basic Error Creation
rust\nuse anyhow::Error;\nuse std::io;\n\nfn main() {\n // Error::new wraps an existing error type\n let io_err = io::Error::new(io::ErrorKind::NotFound, \"file not found\");\n let anyhow_err = Error::new(io_err);\n \n // Error::msg creates an error from a message\n let msg_err = Error::msg(\"something went wrong\");\n \n // Both are anyhow::Error, but created differently\n println!(\"new: {:?}\", anyhow_err);\n println!(\"msg: {:?}\", msg_err);\n}\n\n\nError::new takes an existing error; Error::msg takes a message.
Source Chain Differences
rust\nuse anyhow::Error;\nuse std::error::Error as StdError;\nuse std::io;\n\nfn main() {\n // Error::new preserves source chain\n let io_err = io::Error::new(io::ErrorKind::PermissionDenied, \"access denied\");\n let anyhow_err = Error::new(io_err);\n \n // Can access underlying error via source()\n if let Some(source) = anyhow_err.source() {\n println!(\"Source: {:?}\", source);\n // Source: PermissionDenied\n }\n \n // Error::msg has no source\n let msg_err = Error::msg(\"operation failed\");\n \n // No underlying cause\n if let Some(source) = msg_err.source() {\n println!(\"Source: {:?}\", source);\n } else {\n println!(\"No source\"); // Prints \"No source\"\n }\n}\n\n\nError::new preserves the source chain; Error::msg has no source.
Type Constraints
rust\nuse anyhow::Error;\nuse std::io;\n\n// Error::new requires: E: Error + Send + Sync + 'static\n// This works because io::Error implements std::error::Error\nlet io_err = io::Error::new(io::ErrorKind::Other, \"test\");\nlet anyhow_err = Error::new(io_err);\n\n// Error::msg requires: M: Display + Debug + Send + Sync + 'static\n// Strings and &str satisfy this\nlet msg_err = Error::msg(\"simple message\");\nlet msg_err2 = Error::msg(String::from(\"owned message\"));\n\n// Error::new does NOT work with plain strings\n// let err = Error::new(\"not an error type\"); // Doesn't compile!\n// \"str\" doesn't implement std::error::Error\n\n// Error::msg does NOT work with error types\n// let err = Error::msg(io::Error::new(io::ErrorKind::Other, \"test\"));\n// This would work but is unusual - it uses Display, not Error\n\n\nError::new requires std::error::Error implementation; Error::msg requires Display.
Wrapping Custom Errors
rust\nuse anyhow::Error;\nuse std::fmt;\n\n#[derive(Debug)]\nenum DatabaseError {\n ConnectionFailed(String),\n QueryFailed(String),\n}\n\nimpl fmt::Display for DatabaseError {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n match self {\n DatabaseError::ConnectionFailed(msg) => write!(f, \"Connection failed: {}\", msg),\n DatabaseError::QueryFailed(msg) => write!(f, \"Query failed: {}\", msg),\n }\n }\n}\n\nimpl std::error::Error for DatabaseError {}\n\nfn main() {\n // Error::new wraps our custom error\n let db_err = DatabaseError::ConnectionFailed(\"timeout\".into());\n let anyhow_err = Error::new(db_err);\n \n // Source chain preserved\n if let Some(source) = anyhow_err.source() {\n println!(\"Source: {:?}\", source);\n // Can downcast back to DatabaseError\n }\n}\n\n\nError::new preserves custom error types for downcasting.
Ad-hoc Errors with msg
rust\nuse anyhow::Error;\n\nfn main() {\n // Error::msg for ad-hoc errors without underlying cause\n // Useful for validation failures, assertions, etc.\n \n fn validate_age(age: i32) -> Result<(), Error> {\n if age < 0 {\n return Err(Error::msg(\"age cannot be negative\"));\n }\n if age > 150 {\n return Err(Error::msg(\"age seems unrealistic\"));\n }\n Ok(())\n }\n \n // These aren't wrapping other errors, just business logic failures\n let result = validate_age(-5);\n assert!(result.is_err());\n}\n\n\nError::msg is ideal for business logic failures without underlying errors.
anyhow! Macro Shorthand
rust\nuse anyhow::anyhow;\n\nfn main() {\n // anyhow! macro can do both\n \n // With format string: creates msg error\n let err = anyhow!(\"something went wrong\");\n let err2 = anyhow!(\"value is {}\", 42);\n \n // With error: wraps like Error::new\n let io_err = std::io::Error::new(std::io::ErrorKind::Other, \"io failed\");\n let err3 = anyhow!(io_err);\n \n // Note: anyhow! uses Error::msg for strings, Error::new for errors\n}\n\n\nThe anyhow! macro chooses msg or new based on input type.
Context Trait
rust\nuse anyhow::{Context, Error};\nuse std::fs::File;\n\nfn main() -> Result<(), Error> {\n // .context() adds context to existing errors\n let file = File::open(\"config.txt\")\n .context(\"failed to open config file\")?;\n \n // This uses Error::new internally for the io::Error,\n // then wraps with context message\n \n // Equivalent to:\n let file = File::open(\"config.txt\")\n .map_err(|e| Error::new(e).context(\"failed to open config file\"))?;\n \n Ok(())\n}\n\n\n.context() combines Error::new with additional context.
Downcasting Differences
rust\nuse anyhow::Error;\nuse std::io;\n\nfn main() {\n // Error::new: can downcast to original type\n let io_err = io::Error::new(io::ErrorKind::NotFound, \"file missing\");\n let anyhow_err = Error::new(io_err);\n \n // Downcast back to io::Error\n if let Some(io_error) = anyhow_err.downcast_ref::<io::Error>() {\n println!(\"IO error kind: {:?}\", io_error.kind());\n }\n \n // Error::msg: can only downcast to the message type\n let msg_err = Error::msg(\"something failed\");\n \n // Can't downcast to an error type\n // msg_err.downcast_ref::<io::Error>() // Returns None\n \n // The message is stored internally, not as a standard error type\n}\n\n\nError::new enables downcasting to original type; Error::msg doesn't.
Message Type Flexibility
rust\nuse anyhow::Error;\n\nfn main() {\n // Error::msg accepts any Display type\n let err1 = Error::msg(\"static str\");\n let err2 = Error::msg(String::from(\"owned string\"));\n let err3 = Error::msg(format!(\"formatted {}\", \"message\"));\n \n // Custom Display types work too\n struct CustomMessage {\n code: i32,\n text: String,\n }\n \n impl std::fmt::Display for CustomMessage {\n fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n write!(f, \"Error {}: {}\", self.code, self.text)\n }\n }\n \n let msg = CustomMessage { code: 404, text: \"Not found\".into() };\n let err4 = Error::msg(msg);\n \n println!(\"Error: {}\", err4); // Error: Error 404: Not found\n}\n\n\nError::msg accepts any type implementing Display.
Wrapping External Library Errors
rust\nuse anyhow::Error;\n\n// External library errors are wrapped with Error::new\nfn parse_config(content: &str) -> Result<Config, Error> {\n // serde_json errors implement std::error::Error\n let value: serde_json::Value = serde_json::from_str(content)\n .map_err(Error::new)?;\n \n // This preserves the full error chain from serde_json\n Ok(Config { value })\n}\n\nstruct Config {\n value: serde_json::Value,\n}\n\nfn main() {\n let result = parse_config(\"invalid json\");\n if let Err(e) = result {\n // Can access the underlying serde_json::Error via source()\n if let Some(json_err) = e.source().and_then(|s| s.downcast_ref::<serde_json::Error>()) {\n println!(\"JSON error: {:?}\", json_err);\n }\n }\n}\n\n\nError::new is idiomatic for wrapping external library errors.
Creating Root Errors
rust\nuse anyhow::Error;\n\nfn main() {\n // \"Root\" errors: no underlying cause\n // Use Error::msg for these\n \n // Business rule violations\n fn check_balance(balance: i32, withdrawal: i32) -> Result<i32, Error> {\n if withdrawal > balance {\n return Err(Error::msg(\"insufficient funds\"));\n }\n Ok(balance - withdrawal)\n }\n \n // Validation failures\n fn validate_email(email: &str) -> Result<(), Error> {\n if !email.contains('@') {\n return Err(Error::msg(\"invalid email format\"));\n }\n Ok(())\n }\n \n // Assertion failures in tests\n fn run_test() -> Result<(), Error> {\n let result = compute();\n if result != 42 {\n return Err(Error::msg(format!(\"expected 42, got {}\", result)));\n }\n Ok(())\n }\n \n fn compute() -> i32 { 42 }\n}\n\n\nError::msg creates root errors for validation and business logic.
Error Chain Construction
rust\nuse anyhow::{Error, Context};\nuse std::fs::File;\n\nfn main() -> Result<(), Error> {\n // Building error chains\n \n // Approach 1: Error::new then context\n let result = File::open(\"nonexistent.txt\");\n let err = result.map_err(|e| Error::new(e).context(\"opening config\"))?;\n \n // Approach 2: Context trait (preferred)\n let result = File::open(\"nonexistent.txt\")\n .context(\"opening config\")?;\n // Context internally uses Error::new\n \n // Approach 3: Error::msg for root cause\n // When there's no underlying error to wrap\n let err = Error::msg(\"config file missing\")\n .context(\"initialization failed\");\n \n Ok(())\n}\n\n\nError::new starts chains from existing errors; Error::msg starts chains from messages.
Performance Considerations
rust\nuse anyhow::Error;\n\nfn main() {\n // Error::new: wraps existing allocation\n // The io::Error already exists, we just wrap it\n let io_err = std::io::Error::new(std::io::ErrorKind::Other, \"test\");\n let err = Error::new(io_err);\n // Minimal overhead: just the anyhow wrapper\n \n // Error::msg: allocates to store the message\n let err = Error::msg(\"error message\");\n // Allocates to store \"error message\" internally\n \n // For very hot paths, reusing errors or using Error::new\n // with a static error type may be preferred\n}\n\n\nBoth allocate; Error::new wraps existing error, Error::msg stores message.
Error Conversion Pattern
rust\nuse anyhow::Error;\n\n// Common pattern: converting Result<T, E> to Result<T, Error>\n\n// Using Error::new explicitly\nfn load_file(path: &str) -> Result<String, Error> {\n std::fs::read_to_string(path).map_err(Error::new)\n}\n\n// Using ? with Into conversion\nfn load_file_auto(path: &str) -> Result<String, Error> {\n // This calls Error::new internally due to From implementation\n Ok(std::fs::read_to_string(path)?)\n}\n\n// The From implementation for Error calls Error::new\n// impl<E: std::error::Error + Send + Sync + 'static> From<E> for Error\n\n\nThe From implementation uses Error::new for automatic conversion.
When to Use Each
rust\nuse anyhow::Error;\n\nfn main() -> Result<(), Error> {\n // Use Error::new when:\n // 1. You have an existing error type\n // 2. You want to preserve the error chain\n // 3. Downcasting to original type is needed\n // 4. Wrapping external library errors\n \n let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, \"file\");\n let _ = Error::new(io_err);\n \n // Use Error::msg when:\n // 1. Creating root errors without underlying cause\n // 2. Validation failures\n // 3. Business logic violations\n // 4. Quick error creation in scripts/tools\n \n let _ = Error::msg(\"validation failed\");\n \n // Alternative: use context() for both cases\n // .context() wraps errors with additional info\n \n Ok(())\n}\n\n\nChoose based on whether you have an underlying error to preserve.
Format String with msg
rust\nuse anyhow::Error;\n\nfn main() {\n // Error::msg with formatted strings\n let value = 42;\n let err = Error::msg(format!(\"invalid value: {}\", value));\n \n // Note: Error::msg doesn't support format args directly\n // Use format! or the anyhow! macro\n \n // anyhow! macro is more ergonomic for formatted messages\n use anyhow::anyhow;\n let err = anyhow!(\"invalid value: {}\", value);\n // This uses Error::msg internally\n}\n\n\nError::msg requires format! for dynamic messages; anyhow! handles formatting.
Combining Both Approaches
rust\nuse anyhow::{Error, Context, anyhow};\nuse std::fs::File;\nuse std::io::Read;\n\nfn load_config(path: &str) -> Result<Config, Error> {\n // Start with potential io::Error (wrapped via Error::new)\n let mut file = File::open(path)\n .context(format!(\"failed to open config file: {}\", path))?;\n \n let mut content = String::new();\n file.read_to_string(&mut content)\n .context(\"failed to read config file\")?;\n \n // Validate content - use Error::msg for validation errors\n if content.is_empty() {\n return Err(anyhow!(\"config file is empty\"));\n }\n \n // Parse - could fail with custom error\n parse_config(&content)\n}\n\nfn parse_config(content: &str) -> Result<Config, Error> {\n if content.starts_with('#') {\n // Business logic error - use Error::msg\n return Err(Error::msg(\"config cannot start with comment\"));\n }\n \n // Parse logic...\n Ok(Config { content: content.to_string() })\n}\n\nstruct Config {\n content: String,\n}\n\n\nUse Error::new (via .context() or ?) for external errors, Error::msg for validation.
