Loading pageā¦
Rust walkthroughs
Loading pageā¦
{"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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
std::error::Error\n- Preserves source chain for error inspection\n- Enables downcasting to original error type\n- Used automatically by ? operator for conversion\n\nError::msg purpose:\n- Creates ad-hoc errors from messages\n- Produces root errors with no source\n- Accepts any Display type\n- Ideal for validation and business logic failures\n\nType requirements:\n- Error::new: E: Error + Send + Sync + 'static\n- Error::msg: M: Display + Debug + Send + Sync + 'static\n\nError chains:\n- Error::new: wraps existing errors, maintains chain\n- Error::msg: creates new chain root\n- .context(): adds context layer to either\n\nDowncasting:\n- Error::new: downcast_ref::<E>() works\n- Error::msg: no original type to downcast\n\nWhen to use Error::new:\n- Wrapping external library errors\n- Preserving error type for downcasting\n- Building error chains from known errors\n- Converting Result<T, E> to Result<T, Error>\n\nWhen to use Error::msg:\n- Validation failures\n- Business rule violations\n- Assertion errors\n- Root errors without underlying cause\n\nKey insight: Error::new and Error::msg represent two different error creation patterns: wrapping existing errors versus creating new ones. Error::new is for propagating and enriching errors that come from other codeāI/O errors, parse errors, network errorsāpreserving their type and source chain so callers can inspect or downcast them. Error::msg is for creating errors from within your own logic when there's no underlying error to propagateāvalidation failures, precondition violations, or any "this went wrong" situation where you just need to return an error with a message. The anyhow! macro and .context() method are convenience wrappers: anyhow!(\"message\") uses Error::msg internally, while .context() uses Error::new to wrap the error and then adds a context layer. In practice, you'll use Error::msg (or anyhow!) for validation and business logic errors, and Error::new (or ? with automatic conversion, or .context()) for wrapping and propagating errors from external code.","path":"/articles/266_anyhow_error_new_vs_msg.md"}}