{"id":34716012,"url":"https://github.com/emiliogrv/errors","last_synced_at":"2026-04-25T00:01:25.655Z","repository":{"id":319738131,"uuid":"1079447943","full_name":"emiliogrv/errors","owner":"emiliogrv","description":"High-performance structured error handling for Go. Drop-in replacement for errors package with zero-reflection marshalers and logging framework integration.","archived":false,"fork":false,"pushed_at":"2026-04-23T21:04:35.000Z","size":138,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T23:10:43.277Z","etag":null,"topics":["code-generation","debugging","error-handling","error-wrapping","errors","go","golang","logging","logrus","observability","performance","slog","structured-logging","zap","zerolog"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emiliogrv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-19T20:29:06.000Z","updated_at":"2026-04-23T21:02:37.000Z","dependencies_parsed_at":"2025-10-29T03:18:14.650Z","dependency_job_id":"76277f78-4f21-459c-8ee6-98f5bb536b19","html_url":"https://github.com/emiliogrv/errors","commit_stats":null,"previous_names":["emiliogrv/errors"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/emiliogrv/errors","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emiliogrv%2Ferrors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emiliogrv%2Ferrors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emiliogrv%2Ferrors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emiliogrv%2Ferrors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emiliogrv","download_url":"https://codeload.github.com/emiliogrv/errors/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emiliogrv%2Ferrors/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32245151,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generation","debugging","error-handling","error-wrapping","errors","go","golang","logging","logrus","observability","performance","slog","structured-logging","zap","zerolog"],"created_at":"2025-12-25T00:56:43.239Z","updated_at":"2026-04-25T00:01:25.649Z","avatar_url":"https://github.com/emiliogrv.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n[![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.18-blue)](https://go.dev/)\n[![License](https://img.shields.io/badge/license-BSD--3--Clause-green)](LICENSE)\n\n\u003c/div\u003e\n\n\u003c!-- mdformat-toc start --slug=github --maxlevel=6 --minlevel=1 --\u003e\n\n- [Overview](#overview)\n- [Performance](#performance)\n- [Features](#features)\n  - [Core Functionality](#core-functionality)\n  - [Partial Imports](#partial-imports)\n  - [Custom Template Generation](#custom-template-generation)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Error Creation](#basic-error-creation)\n  - [Error Wrapping](#error-wrapping)\n  - [Logging Integration](#logging-integration)\n    - [Full Import Example](#full-import-example)\n    - [Partial Import Example](#partial-import-example)\n  - [Custom Template Example](#custom-template-example)\n- [Templates](#templates)\n  - [Core Templates](#core-templates)\n  - [Logger Templates](#logger-templates)\n  - [Template Overriding](#template-overriding)\n- [Generator Usage](#generator-usage)\n  - [Examples](#examples)\n- [API Reference](#api-reference)\n  - [Core Types](#core-types)\n    - [`StructuredError`](#structurederror)\n    - [`Attr`](#attr)\n  - [Core Functions](#core-functions)\n  - [Attribute Helpers](#attribute-helpers)\n  - [Methods](#methods)\n    - [`*StructuredError` Methods](#structurederror-methods)\n  - [Configuration](#configuration)\n- [Drop-in Replacement Compatibility](#drop-in-replacement-compatibility)\n  - [Known Differences](#known-differences)\n    - [1. Text Loss with Nested `fmt.Errorf` Wrappers](#1-text-loss-with-nested-fmterrorf-wrappers)\n    - [2. String Output Format](#2-string-output-format)\n    - [3. `Unwrap()` and Serialization Behavior](#3-unwrap-and-serialization-behavior)\n  - [Compatibility Testing](#compatibility-testing)\n- [API Stability](#api-stability)\n- [Examples](#examples-1)\n- [Contributing](#contributing)\n- [License](#license)\n- [Acknowledgments](#acknowledgments)\n\n\u003c!-- mdformat-toc end --\u003e\n\n______________________________________________________________________\n\n## Overview\u003ca name=\"overview\"\u003e\u003c/a\u003e\n\nThis **ready-to-use** library provides **structured error handling** for Go applications, designed as a complete drop-in\nreplacement for the standard `errors` package. It extends standard error functionality with:\n\n- **Structured attributes** for rich error context\n- **Error wrapping and joining** with full compatibility with `errors.Is`, `errors.As`, and `errors.Join`\n- **Stack trace capture** for debugging\n- **JSON serialization** for structured logging\n- **Direct integration** with popular logging frameworks (Zap, Zerolog, Logrus, slog)\n- **Customizable code generation** for your own logging frameworks\n\n## Performance\u003ca name=\"performance\"\u003e\u003c/a\u003e\n\nThis library is designed with **performance as a core principle**. The primary goal is to provide meaningful, structured\nerror messages with **maximum performance** by:\n\n- **Avoiding reflection** wherever possible - type-safe attribute helpers eliminate runtime reflection overhead\n- **Zero-allocation string building** for common error formatting paths\n- **Efficient marshaling** - custom marshalers for each logging framework avoid generic reflection-based serialization\n- **Lazy evaluation** - error details are only formatted when actually logged or serialized\n- **Minimal allocations** - careful memory management to reduce GC pressure\n\n## Features\u003ca name=\"features\"\u003e\u003c/a\u003e\n\n### Core Functionality\u003ca name=\"core-functionality\"\u003e\u003c/a\u003e\n\nThe library maintains full compatibility with Go's standard `errors` package while adding powerful structured error\nhandling capabilities:\n\n```go\nimport errors \"github.com/emiliogrv/errors/pkg/full\"\n\nerr := errors.New(\"database connection failed\").\nWithAttrs(\nerrors.String(\"host\", \"localhost\"),\nerrors.Int(\"port\", 5432),\nerrors.Duration(\"timeout\", 30*time.Second),\n).\nWithTags(\"database\", \"critical\").\nWithStack(debug.Stack())\n```\n\n### Partial Imports\u003ca name=\"partial-imports\"\u003e\u003c/a\u003e\n\n**Import only what you need!** To avoid pulling all logging framework dependencies into your `go.mod`, you can import\nspecific logger packages:\n\n```go\n// Import only Zap support\nimport errors \"github.com/emiliogrv/errors/pkg/zap\"\n\n// Import only slog support\nimport errors \"github.com/emiliogrv/errors/pkg/slog\"\n\n// Import only Logrus support\nimport errors \"github.com/emiliogrv/errors/pkg/logrus\"\n\n// Import only Zerolog support\nimport errors \"github.com/emiliogrv/errors/pkg/zerolog\"\n\n// Import only core functionality (no logger integrations)\nimport errors \"github.com/emiliogrv/errors/pkg/core\"\n```\n\nEach partial import includes the core templates plus the specific logger integration, keeping your dependencies minimal.\n\n### Custom Template Generation\u003ca name=\"custom-template-generation\"\u003e\u003c/a\u003e\n\nThe library supports **custom template generation**, allowing you to:\n\n1. **Generate your own logger integrations** by providing custom templates\n1. **Override default templates** to customize behavior\n1. **Add new functionality** by simply using the `-input-dir` flag with your template directory\n\nExample:\n\n```bash\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -input-dir ./my-templates \\\n    -output-dir ./generated \\\n    -formats mylogger,zap\n```\n\n**Core templates are always generated** regardless of which formats you specify, ensuring base functionality is always\navailable.\n\n## Installation\u003ca name=\"installation\"\u003e\u003c/a\u003e\n\n```bash\ngo get github.com/emiliogrv/errors\n```\n\n## Usage\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n### Basic Error Creation\u003ca name=\"basic-error-creation\"\u003e\u003c/a\u003e\n\n```go\nimport errors \"github.com/emiliogrv/errors/pkg/full\"\n\n// Simple error\nerr := errors.New(\"something went wrong\")\n\n// Error with attributes\nerr := errors.New(\"failed to process request\").\nWithAttrs(\nerrors.String(\"user_id\", \"12345\"),\nerrors.Int(\"retry_count\", 3),\nerrors.Bool(\"recoverable\", true),\n)\n```\n\n### Error Wrapping\u003ca name=\"error-wrapping\"\u003e\u003c/a\u003e\n\n```go\n// Wrap errors with context\nif err := doSomething(); err != nil {\n\treturn errors.New(\"operation failed\").\n\t\tWithErrors(err).\n\t\tWithAttrs(errors.String(\"operation\", \"doSomething\"))\n}\n\n// Join multiple errors\nerr := errors.Join(\n\terrors.New(\"validation failed\"),\n\terrors.New(\"missing required field: email\"),\n\terrors.New(\"missing required field: name\"),\n)\n```\n\n### Logging Integration\u003ca name=\"logging-integration\"\u003e\u003c/a\u003e\n\n#### Full Import Example\u003ca name=\"full-import-example\"\u003e\u003c/a\u003e\n\n```go\nimport (\n\terrors \"github.com/emiliogrv/errors/pkg/full\"\n\t\"go.uber.org/zap\"\n)\n\nfunc main() {\n\terr := errors.New(\"operation failed\").\n\t\tWithAttrs(errors.Int(\"code\", 500))\n\n\t// Zap\n\tlogger, _ := zap.NewProduction()\n\tlogger.Error(\"error occurred\", zap.Any(\"err\", err))\n\n\t// JSON marshaling\n\tjsonData, _ := json.Marshal(err)\n\n\t// Logrus\n\tlogrus.WithFields(logrus.Fields{\n\t\t\"err\": err.(*errors.StructuredError).MarshalLogrusFields(),\n\t}).\n\t\tError(\"error occurred\")\n}\n```\n\n#### Partial Import Example\u003ca name=\"partial-import-example\"\u003e\u003c/a\u003e\n\n```go\nimport (\n\terrors \"github.com/emiliogrv/errors/pkg/zap\" // Only Zap dependency\n\t\"go.uber.org/zap\"\n)\n\nfunc main() {\n\terr := errors.New(\"operation failed\").\n\t\tWithAttrs(errors.Int(\"code\", 500))\n\n\tlogger, _ := zap.NewProduction()\n\tlogger.Error(\"error occurred\", zap.Any(\"err\", err))\n}\n```\n\n### Custom Template Example\u003ca name=\"custom-template-example\"\u003e\u003c/a\u003e\n\nCreate your custom template (e.g., `tmpl/mylogger.tmpl`):\n\n```go\n// Code generated by errors_generator; DO NOT EDIT.\n// Generated at {{ .Date }}\n// Version {{ .Version }}\n\npackage {{ .PackageName }}\n\n// MarshalMyLogger is the implementation for MyLogger.\nfunc (receiver *StructuredError) MarshalMyLogger() error {\n    // Your custom marshaling logic here\n    return nil\n}\n```\n\nGenerate code:\n\n```bash\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -input-dir ./tmpl \\\n    -output-dir ./generated \\\n    -formats mylogger\n```\n\n## Templates\u003ca name=\"templates\"\u003e\u003c/a\u003e\n\n### Core Templates\u003ca name=\"core-templates\"\u003e\u003c/a\u003e\n\nCore templates are **always generated** and provide the fundamental error handling functionality:\n\n| Template    | Description                                                           |\n| ----------- | --------------------------------------------------------------------- |\n| `attr.go`   | Type-safe attribute helpers (String, Int, Bool, Time, Duration, etc.) |\n| `common.go` | Common utilities and depth control for marshaling                     |\n| `error.go`  | Core `StructuredError` type and basic methods                         |\n| `join.go`   | `Join` and `JoinIf` functions for combining errors                    |\n| `json.go`   | JSON marshaling/unmarshaling support                                  |\n| `map.go`    | Map representation for generic structured output                      |\n| `string.go` | String formatting and `Error()` method implementation                 |\n| `wrap.go`   | `Unwrap`, `Is`, and `As` methods for error wrapping                   |\n\n### Logger Templates\u003ca name=\"logger-templates\"\u003e\u003c/a\u003e\n\nAdditional templates for specific logging framework integrations:\n\n| Package       | Templates                            | Dependencies                 |\n| ------------- | ------------------------------------ | ---------------------------- |\n| `pkg/full`    | Core + Zap + Zerolog + Logrus + slog | All logger dependencies      |\n| `pkg/zap`     | Core + Zap                           | `go.uber.org/zap`            |\n| `pkg/zerolog` | Core + Zerolog                       | `github.com/rs/zerolog`      |\n| `pkg/logrus`  | Core + Logrus                        | `github.com/sirupsen/logrus` |\n| `pkg/slog`    | Core + slog                          | Standard library only        |\n| `pkg/core`    | Core only                            | No external dependencies     |\n\n### Template Overriding\u003ca name=\"template-overriding\"\u003e\u003c/a\u003e\n\nYou can **override any default template** by providing a template with the same name in your input directory:\n\n```bash\n# Override the default zap.tmpl with your custom version\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -input-dir ./my-templates \\\n    -output-dir ./generated \\\n    -formats zap\n```\n\nIf `my-templates/zap.tmpl` exists, it will replace the built-in Zap template.\n\n## Generator Usage\u003ca name=\"generator-usage\"\u003e\u003c/a\u003e\n\nThe code generator supports various options:\n\n```bash\ngo run github.com/emiliogrv/errors/cmd/errors_generator [options]\n\nOptions:\n  -formats string\n        Comma-separated list of formats to generate, or 'all' to generate all formats (default: core)\n  -help\n        Show this help message\n  -input-dir string\n        Path to user templates directory (optional)\n  -output-dir string\n        Output directory for generated files\n  -export-dir string\n        Export default templates to the specified directory and exit\n  -package string\n        Package name for generated code (default: errors) (default \"errors\")\n  -test-gen string\n        Test generation level: none, flex, strict (default: none) (default \"none\")\n  -version string\n        Version for generated code (auto-detected from git tags if not provided)\n  -with-gen-header\n        Include generated message in generated code (default: true) (default true)\n```\n\n### Examples\u003ca name=\"examples\"\u003e\u003c/a\u003e\n\n```bash\n# Export default templates for customization\ngo run github.com/emiliogrv/errors/cmd/errors_generator -export-dir ./my-templates\n\n# Generate core templates only\ngo run github.com/emiliogrv/errors/cmd/errors_generator -output-dir ./pkg/core\n\n# Generate with Zap support\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -output-dir ./pkg/zap \\\n    -formats zap\n\n# Generate all available formats\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -output-dir ./pkg/full \\\n    -formats all\n\n# Generate with custom templates\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -input-dir ./my-templates \\\n    -output-dir ./generated \\\n    -formats mylogger,zap\n\n# Generate with tests\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -output-dir ./pkg/full \\\n    -formats all \\\n    -test-gen strict\n\n# Generate with specific version\ngo run github.com/emiliogrv/errors/cmd/errors_generator \\\n    -output-dir ./pkg/full \\\n    -formats all \\\n    -version 1.2.3\n```\n\n## API Reference\u003ca name=\"api-reference\"\u003e\u003c/a\u003e\n\n### Core Types\u003ca name=\"core-types\"\u003e\u003c/a\u003e\n\n#### `StructuredError`\u003ca name=\"structurederror\"\u003e\u003c/a\u003e\n\n```go\ntype StructuredError struct {\n\tMessage string   // Primary error message\n\tAttrs   []Attr   // Structured attributes\n\tErrors  []error  // Wrapped errors\n\tTags    []string // Categorical labels\n\tStack   []byte   // Stack trace (optional)\n}\n```\n\n#### `Attr`\u003ca name=\"attr\"\u003e\u003c/a\u003e\n\n```go\ntype Attr struct {\n\tKey   string\n\tValue any\n\tType  Type\n}\n```\n\n### Core Functions\u003ca name=\"core-functions\"\u003e\u003c/a\u003e\n\n- `New(message string) *StructuredError` - Create a new structured error\n- `Join(errs ...error) error` - Join multiple errors (nil-safe)\n- `JoinIf(errs ...error) error` - Join errors only if first is non-nil\n- `Is(err, target error) bool` - Check error equality (alias to `errors.Is`)\n- `As(err error, target any) bool` - Type assertion (alias to `errors.As`)\n- `Unwrap(err error) error` - Unwrap single error (alias to `errors.Unwrap`)\n\n### Attribute Helpers\u003ca name=\"attribute-helpers\"\u003e\u003c/a\u003e\n\nType-safe helpers for common types:\n\n- `String(key, value string) Attr`\n- `Int(key string, value int) Attr`\n- `Int64(key string, value int64) Attr`\n- `Uint64(key string, value uint64) Attr`\n- `Float64(key string, value float64) Attr`\n- `Bool(key string, value bool) Attr`\n- `Time(key string, value time.Time) Attr`\n- `Duration(key string, value time.Duration) Attr`\n- `Any(key string, value any) Attr`\n- `Object(key string, attrs ...Attr) Attr`\n\nEach helper also has a plural version (e.g., `Ints`, `Strings`, `Bools`) for slices.\n\n### Methods\u003ca name=\"methods\"\u003e\u003c/a\u003e\n\n#### `*StructuredError` Methods\u003ca name=\"structurederror-methods\"\u003e\u003c/a\u003e\n\n- `WithAttrs(attrs ...Attr) *StructuredError` - Add attributes\n- `WithErrors(errors ...error) *StructuredError` - Set wrapped errors\n- `WithTags(tags ...string) *StructuredError` - Add tags\n- `WithStack(stack []byte) *StructuredError` - Set stack trace\n- `PrependErrors(errors ...error) *StructuredError` - Add errors at the beginning\n- `AppendErrors(errors ...error) *StructuredError` - Add errors at the end\n- `Error() string` - Implement error interface\n- `Unwrap() []error` - Implement multi-unwrapper interface\n- `MarshalJSON() ([]byte, error)` - JSON marshaling\n- `UnmarshalJSON(data []byte) error` - JSON unmarshaling\n\n### Configuration\u003ca name=\"configuration\"\u003e\u003c/a\u003e\n\n```go\n// Set maximum depth for error marshaling (default: 100)\nerrors.SetMaxDepthMarshal(depth int)\n\n// Get current maximum depth\nerrors.MaxDepthMarshal() int\n```\n\n## Drop-in Replacement Compatibility\u003ca name=\"drop-in-replacement-compatibility\"\u003e\u003c/a\u003e\n\nThis library is designed as a **complete drop-in replacement** for Go's standard `errors` package. You can replace:\n\n```go\nimport \"errors\"\n```\n\nwith:\n\n```go\nimport errors \"github.com/emiliogrv/errors/pkg/full\"\n```\n\nAnd your existing code will continue to work as expected.\n\n### Known Differences\u003ca name=\"known-differences\"\u003e\u003c/a\u003e\n\nWhile this library maintains full API compatibility with the standard `errors` package, there are some behavioral\ndifferences to be aware of:\n\n#### 1. Text Loss with Nested `fmt.Errorf` Wrappers\u003ca name=\"1-text-loss-with-nested-fmterrorf-wrappers\"\u003e\u003c/a\u003e\n\nWhen using `fmt.Errorf` to wrap a `StructuredError`, the text is preserved in the `fmt.Errorf` wrapper. However, **if\nthat wrapped error is then added to another `StructuredError` via `WithErrors()` or `Join()`**, the `fmt.Errorf` wrapper\ntext is lost because the marshaling extracts the inner `StructuredError` directly:\n\n```go\nbase := errors.New(\"base error\")\nwrapped := fmt.Errorf(\"text example %w\", base)\n\n// Text is preserved when calling wrapped.Error() directly:\nfmt.Println(wrapped.Error()) // Output: \"text example (message=base error)\"\n\n// But text is lost when nested in another StructuredError:\nnested := errors.New(\"outer\").WithErrors(wrapped)\nfmt.Println(nested.Error())\n// Output: (message=outer),\n//         (errors=[\n//             (message=base error)\n//         ])\n// The \"text example\" part is lost\n```\n\n**Workaround**: Use structured error capabilities directly instead of mixing `fmt.Errorf` with `WithErrors()`:\n\n```go\nbase := errors.New(\"base error\")\nwrapped := errors.New(\"text example\").WithErrors(base)\n// Now \"text example\" is preserved in the error chain\n```\n\n#### 2. String Output Format\u003ca name=\"2-string-output-format\"\u003e\u003c/a\u003e\n\nThe string representation of errors created with this package may differ from standard errors when using structured\nfeatures:\n\n- **Standard `errors.New()`**: Produces identical output to `errors.New()` from the standard library\n- **With structured features**: Using `WithErrors()`, `WithAttrs()`, etc. produces a different format that includes the\n  structured information\n\n```go\n// These produce identical string output:\nstdErr := stderrors.New(\"error message\")\ncustomErr := errors.New(\"error message\")\n\n// These produce different string output:\nstdWrapped := fmt.Errorf(\"wrapper: %w\", stderrors.New(\"base\"))\ncustomWrapped := errors.New(\"wrapper\").WithErrors(errors.New(\"base\"))\n```\n\n#### 3. `Unwrap()` and Serialization Behavior\u003ca name=\"3-unwrap-and-serialization-behavior\"\u003e\u003c/a\u003e\n\nThis package implements the multi-error unwrapper interface (`Unwrap() []error`), while `fmt.Errorf` with `%w`\nimplements the single-error unwrapper interface (`Unwrap() error`). The key difference is in how `StructuredError`\nserializes wrapped errors:\n\n- **`fmt.Errorf(\"text %w\", err)` on its own**:\n\n  - Preserves all text when calling `.Error()`\n  - Example: `fmt.Errorf(\"text example %w\", err).Error()` shows `\"text example: \u003cerr message\u003e\"`\n  - Implements single-error unwrapper interface\n\n- **`fmt.Errorf` wrapped in `StructuredError`**:\n\n  - When `StructuredError` serializes the error, it calls `Unwrap()` to extract the inner error\n  - `fmt.Errorf` ignores the wrapping text when unwrapped, returning only the inner error\n  - **Result**: The wrapping text is lost during `StructuredError` serialization\n  - Example: `errors.New(\"outer\").WithErrors(fmt.Errorf(\"text example %w\", err))` loses \"text example\"\n\n- **`WithErrors()` wrapped errors**:\n\n  - Preserves all text and structure during serialization\n  - Does not lose context when unwrapped by another `StructuredError`\n  - Implements the multi-unwrap interface for error chaining\n  - Maintains full context in both the error chain and string output\n\nFor example:\n\n```go\n// fmt.Errorf preserves text on its own\nwrapped1 := fmt.Errorf(\"text example %w\", errors.New(\"base error\"))\nfmt.Println(wrapped1.Error()) // =\u003e \"text example: base error\" ✓\n\n// But text is lost when StructuredError unwraps it\nwrapped2 := errors.New(\"outer\").WithErrors(wrapped1)\nfmt.Println(wrapped2.Error()) // =\u003e \"(message=outer), (errors=[(message=base error)])\" - loses \"text example\" ✗\n\n// WithErrors preserves all text\nwrapped3 := errors.New(\"wrapper\").WithErrors(errors.New(\"base error\"))\nfmt.Println(wrapped3.Error()) // =\u003e \"(message=wrapper), (errors=[(message=base error)])\" ✓\n```\n\n### Compatibility Testing\u003ca name=\"compatibility-testing\"\u003e\u003c/a\u003e\n\nThe library includes comprehensive compatibility tests to ensure drop-in replacement behavior. See [\n`pkg/full/compatibility_test.go`](pkg/full/compatibility_test.go) for detailed test cases covering:\n\n- String output comparison between standard and structured errors\n- `errors.Is()` behavior with both error types\n- `errors.As()` behavior for extracting `StructuredError`\n- `errors.Unwrap()` behavior with single and multi-unwrap interfaces\n- `errors.Join()` compatibility\n- Nil error handling\n- `fmt.Errorf` behavior with `%w` verb\n- The known text loss when nesting `fmt.Errorf` wrapped errors in `WithErrors()`\n\n## API Stability\u003ca name=\"api-stability\"\u003e\u003c/a\u003e\n\n⚠️ **Pre-1.0 Notice**: The library API is essentially complete but may undergo changes before version 1.0. While we\nstrive to maintain backward compatibility, breaking changes may occur in minor versions (0.x.y) until the 1.0 release.\n\nOnce version 1.0 is released, the API will follow semantic versioning strictly.\n\n## Examples\u003ca name=\"examples-1\"\u003e\u003c/a\u003e\n\nComplete examples are available in the [examples/](examples/) directory:\n\n- [full import](examples/full_import/) - Full import with all logger integrations\n- [partial import](examples/partial_import/) - Partial import (Zap only)\n- [custom tmpl](examples/custom_tmpl/) - Custom template generation\n\n## Contributing\u003ca name=\"contributing\"\u003e\u003c/a\u003e\n\nContributions are welcome! Please feel free to submit issues or pull requests.\n\n## License\u003ca name=\"license\"\u003e\u003c/a\u003e\n\nThis project is licensed under the BSD 3-Clause License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\u003ca name=\"acknowledgments\"\u003e\u003c/a\u003e\n\nThis library is designed to be a drop-in replacement for Go's standard `errors` package while providing enhanced\nfunctionality for modern application development.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femiliogrv%2Ferrors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femiliogrv%2Ferrors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femiliogrv%2Ferrors/lists"}