{"id":13694181,"url":"https://github.com/ansel1/merry","last_synced_at":"2026-01-30T12:30:44.737Z","repository":{"id":34926747,"uuid":"38988049","full_name":"ansel1/merry","owner":"ansel1","description":"Golang errors with stacktrace and context","archived":false,"fork":false,"pushed_at":"2025-10-08T16:05:39.000Z","size":349,"stargazers_count":278,"open_issues_count":0,"forks_count":11,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-08T18:33:42.777Z","etag":null,"topics":["errors","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ansel1.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}},"created_at":"2015-07-13T02:49:49.000Z","updated_at":"2025-10-08T16:03:55.000Z","dependencies_parsed_at":"2025-05-03T01:42:06.713Z","dependency_job_id":"60f57be9-8533-47d6-b925-78999a4b2b00","html_url":"https://github.com/ansel1/merry","commit_stats":null,"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/ansel1/merry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansel1%2Fmerry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansel1%2Fmerry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansel1%2Fmerry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansel1%2Fmerry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ansel1","download_url":"https://codeload.github.com/ansel1/merry/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ansel1%2Fmerry/sbom","scorecard":{"id":198031,"data":{"date":"2025-08-11","repo":{"name":"github.com/ansel1/merry","commit":"4af731f0ef8c34d06f97351f2a1185424034bc48"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/ansel1/merry/go.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/ansel1/merry/go.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 3 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T22:11:50.032Z","repository_id":34926747,"created_at":"2025-08-16T22:11:50.032Z","updated_at":"2025-08-16T22:11:50.032Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28912911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"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":["errors","golang"],"created_at":"2024-08-02T17:01:26.133Z","updated_at":"2026-01-30T12:30:44.706Z","avatar_url":"https://github.com/ansel1.png","language":"Go","funding_links":[],"categories":["开源类库","Open source library"],"sub_categories":["错误处理","Error Handling"],"readme":"merry [![Build](https://github.com/ansel1/merry/workflows/Build/badge.svg)](https://github.com/ansel1/merry/actions?query=branch%3Amaster+workflow%3ABuild+) [![GoDoc](https://godoc.org/github.com/ansel1/merry?status.png)](https://godoc.org/github.com/ansel1/merry) [![Go Report Card](https://goreportcard.com/badge/github.com/ansel1/merry)](https://goreportcard.com/report/github.com/ansel1/merry)\n=====\n\nAdd context to errors, including automatic stack capture, cause chains, HTTP status code, user\nmessages, and arbitrary values.\n            \nThe package is largely based on http://github.com/go-errors/errors, with additional\ninspiration from https://github.com/go-errgo/errgo and https://github.com/amattn/deeperror.\n\nV2\n-- \n\n[github.com/ansel1/merry/v2](https://github.com/ansel1/merry/tree/master/v2) now replaces v1.  v1 will continue to be supported.  v1 has been re-implemented\nin terms of v2, and the two packages can be used together and interchangeably.\n\nThere are some small enhancements and changes to v1 with the introduction of v2:\n\n- err.Error() now *always* just prints out the basic error message.  It no longer prints out details,\n  user message, or cause.  VerboseDefault() and SetVerboseDefault() no longer have any effect.  To \n  print more detailed error information, you must use fmt:\n  \n        // print err message and cause chain\n        fmt.Printf(\"%v\", err)    // %s works too\n  \n        // print details, same as Details(err)\n        fmt.Printf(\"%v+\", err) \n  \n- MaxStackDepth is no longer supported.  Setting it has no effect.  It has been replaced with\n  GetMaxStackDepth() and SetMaxStackDepth(), which delegate to corresponding v2 functions.\n- New, Errorf, Wrap, and WrapSkipping now accept v2.Wrapper arguments, allowing a mixture of \n  v1's fluent API style and v2's option-func API style.\n- Compatibility with other error wrapping libraries is improved.  All functions which extract\n  a value from an error will now search the entire chain of errors, even if errors created by\n  other libraries are inserted in the middle of the chain, so long as those errors implement\n  Unwrap().\n\nInstallation\n------------\n\n    go get github.com/ansel1/merry\n    \nFeatures\n--------\n\nMerry errors work a lot like google's golang.org/x/net/context package.\nMerry errors wrap normal errors with a context of key/value pairs.\nLike contexts, merry errors are immutable: adding a key/value to an error\nalways creates a new error which wraps the original.  \n\n`merry` comes with built-in support for adding information to errors:\n\n* stacktraces\n* overriding the error message\n* HTTP status codes\n* End user error messages\n \nYou can also add your own additional information.\n\nThe stack capturing feature can be turned off for better performance, though it's pretty fast.  Benchmarks\non an 2017 MacBook Pro, with go 1.10:\n\n    BenchmarkNew_withStackCapture-8      \t 2000000\t       749 ns/op\n    BenchmarkNew_withoutStackCapture-8   \t20000000\t        64.1 ns/op\n\nDetails\n-------\n\n* Support for go 2's errors.Is and errors.As functions\n* New errors have a stacktrace captured where they are created\n* Add a stacktrace to existing errors (captured where they are wrapped)\n\n    ```go\n    err := lib.Read()\n    return merry.Wrap(err)  // no-op if err is already merry\n    ```\n        \n* Add a stacktrace to a sentinel error\n\n    ```go\n    var ParseError = merry.New(\"parse error\")\n    \n    func Parse() error {\n    \t// ...\n        return ParseError.Here() // captures a stacktrace here\n    }\n    ```\n  \n* The golang idiom for testing errors against sentinel values or type checking them\n  doesn't work with merry errors, since they are wrapped.  Use Is() for sentinel value\n  checks, or the new go 2 errors.As() function for testing error types. \n  \n    ```go\n    err := Parse()\n  \n    // sentinel value check\n    if merry.Is(err, ParseError) {\n       // ...\n    }\n  \n    // type check\n    if serr, ok := merry.Unwrap(err).(*SyntaxError); ok {\n      // ...\n    }\n  \n    // these only work in go1.13\n    \n    // sentinel value check\n    if errors.Is(err, ParseError) {}\n  \n    // type check\n    var serr *SyntaxError\n    if errors.As(err, \u0026serr) {}\n    ```\n        \n* Add to the message on an error.\n\n    ```go\n    err := merry.Prepend(ParseError, \"reading config\").Append(\"bad input\")\n    fmt.Println(err.Error()) // reading config: parse error: bad input\n    ```\n        \n* Hierarchies of errors\n\n    ```go\n    var ParseError = merry.New(\"Parse error\")\n    var InvalidCharSet = merry.WithMessage(ParseError, \"Invalid char set\")\n    var InvalidSyntax = merry.WithMessage(ParseError, \"Invalid syntax\")\n    \n    func Parse(s string) error {\n        // use chainable methods to add context\n        return InvalidCharSet.Here().WithMessagef(\"Invalid char set: %s\", \"UTF-8\")\n        // or functions\n        // return merry.WithMessagef(merry.Here(InvalidCharSet), \"Invalid char set: %s\", \"UTF-8\")\n    }\n    \n    func Check() {\n        err := Parse(\"fields\")\n        merry.Is(err, ParseError) // yup\n        merry.Is(err, InvalidCharSet) // yup\n        merry.Is(err, InvalidSyntax) // nope\n    }\n    ```\n        \n* Add an HTTP status code\n\n    ```go\n    merry.HTTPCode(errors.New(\"regular error\")) // 500\n    merry.HTTPCode(merry.New(\"merry error\").WithHTTPCode(404)) // 404\n    ```\n\n* Set an alternate error message for end users\n \n    ```go\n    e := merry.New(\"crash\").WithUserMessage(\"nothing to see here\")\n    merry.UserMessage(e)  // returns \"nothing to see here\"\n    ```\n        \n* Functions for printing error details\n \n    ```go\n    err := merry.New(\"boom\")\n    m := merry.Stacktrace(err) // just the stacktrace\n    m = merry.Details(err) // error message and stacktrace\n    fmt.Sprintf(\"%+v\", err) == merry.Details(err) // errors implement fmt.Formatter\n    ```\n   \n* Add your own context info\n\n    ```go\n    err := merry.New(\"boom\").WithValue(\"explosive\", \"black powder\")\n    ```\n    \nBasic Usage\n-----------\n\nThe package contains functions for creating new errors with stacks, or adding a stack to `error` \ninstances.  Functions with add context (e.g. `WithValue()`) work on any `error`, and will \nautomatically convert them to merry errors (with a stack) if necessary.\n\nCapturing the stack can be globally disabled with `SetStackCaptureEnabled(false)`\n\nFunctions which get context values from errors also accept `error`, and will return default\nvalues if the error is not merry, or doesn't have that key attached.\n\nAll the functions which create or attach context return concrete instances of `*Error`.  `*Error`\nimplements methods to add context to the error (they mirror the functions and do\nthe same thing).  They allow for a chainable syntax for adding context.\n\nExample:\n\n```go\npackage main\n\nimport (\n    \"github.com/ansel1/merry\"\n    \"errors\"\n)\n\nvar InvalidInputs = errors.New(\"Input is invalid\")\n\nfunc main() {\n    // create a new error, with a stacktrace attached\n    err := merry.New(\"bad stuff happened\")\n    \n    // create a new error with format string, like fmt.Errorf\n    err = merry.Errorf(\"bad input: %v\", os.Args)\n    \n    // capture a fresh stacktrace from this callsite\n    err = merry.Here(InvalidInputs)\n    \n    // Make err merry if it wasn't already.  The stacktrace will be captured here if the\n    // error didn't already have one.  Also useful to cast to *Error \n    err = merry.Wrap(err, 0)\n\n    // override the original error's message\n    err.WithMessagef(\"Input is invalid: %v\", os.Args)\n    \n    // Use Is to compare errors against values, which is a common golang idiom\n    merry.Is(err, InvalidInputs) // will be true\n    \n    // associated an http code\n    err.WithHTTPCode(400)\n    \n    perr := parser.Parse(\"blah\")\n    err = Wrap(perr, 0)\n    // Get the original error back\n    merry.Unwrap(err) == perr  // will be true\n    \n    // Print the error to a string, with the stacktrace, if it has one\n    s := merry.Details(err)\n    \n    // Just print the stacktrace (empty string if err is not a RichError)\n    s := merry.Stacktrace(err)\n\n    // Get the location of the error (the first line in the stacktrace)\n    file, line := merry.Location(err)\n    \n    // Get an HTTP status code for an error.  Defaults to 500 for non-nil errors, and 200 if err is nil.\n    code := merry.HTTPCode(err)\n    \n}\n```\n    \nSee inline docs for more details.\n\nPlugs\n-----\n\n- Check out my HTTP client library: [github.com/gemalto/requester](https://github.com/gemalto/requester)\n- Check out my log library: [github.com/gemalto/flume](https://github.com/gemalto/flume)\n\nLicense\n-------\n\nThis package is licensed under the MIT license, see LICENSE.MIT for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansel1%2Fmerry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fansel1%2Fmerry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fansel1%2Fmerry/lists"}