{"id":43986546,"url":"https://github.com/setlog/panik","last_synced_at":"2026-02-07T10:03:53.788Z","repository":{"id":48122987,"uuid":"236725398","full_name":"setlog/panik","owner":"setlog","description":"An amalgamation of error and panic()","archived":false,"fork":false,"pushed_at":"2021-08-05T15:23:15.000Z","size":73,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-08-15T03:58:54.353Z","etag":null,"topics":[],"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/setlog.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-28T12:02:10.000Z","updated_at":"2022-04-06T11:26:37.000Z","dependencies_parsed_at":"2022-08-12T19:01:12.997Z","dependency_job_id":null,"html_url":"https://github.com/setlog/panik","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/setlog/panik","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setlog%2Fpanik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setlog%2Fpanik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setlog%2Fpanik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setlog%2Fpanik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/setlog","download_url":"https://codeload.github.com/setlog/panik/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/setlog%2Fpanik/sbom","scorecard":{"id":813472,"data":{"date":"2025-08-11","repo":{"name":"github.com/setlog/panik","commit":"dca85566644c88cdc47fba0a61017f7fc1c2f08a"},"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/30 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":"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":"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":"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":"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"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:11: update your workflow using https://app.stepsecurity.io/secureworkflow/setlog/panik/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/setlog/panik/go.yml/master?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":"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":"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":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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":"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-23T13:40:22.601Z","repository_id":48122987,"created_at":"2025-08-23T13:40:22.601Z","updated_at":"2025-08-23T13:40:22.601Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29191994,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T07:37:03.739Z","status":"ssl_error","status_checked_at":"2026-02-07T07:37:03.029Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":[],"created_at":"2026-02-07T10:03:53.011Z","updated_at":"2026-02-07T10:03:53.781Z","avatar_url":"https://github.com/setlog.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# panik ![](https://github.com/setlog/panik/workflows/Tests/badge.svg)\n\nAn error-handling paradigm for Go.\n\n## The problem\n\n```go\nerr := doSomething()\nif err != nil {\n    panic(err)\n}\n```\n\nFrom the view of idiomatic Go, the above code has two problems:\n1. An error is turned into a panic, making a treatable problem look like an untreatable one.\n    * Even worse, it makes a treatable problem turn invisible, since a function signature does not inform about potential panics.\n2. The error `err` will lack contextual information once it gets `recover()`ed, since no calls of the form `fmt.Errorf(\"-context-: %w\", err)` are being made.\n\nTo alleviate these problems:\n1. Call `recover()` before stepping over an API boundary.\n    * If the recovered value isn't our error, assume the worst and `panic()` again.\n2. There are errors where information on its circumstances aren't typically needed. Only use this technique with those. An example of this might be file IO: if the call fails, it is exceedingly likely that the cause is going to have to do with issues in the environment (disk full, missing permissions) which fall outside of the program's responsibility, or even control.\n\nWith those constraints in mind, we can help us out with a package such as this.\n\n## panik's API and how to use it\n\nThe key-concept of panik is to reduce the amount of error-handling code by triggering a panic in places where you would otherwise return an error. As the stack unwinds, the panic may eventually be recovered (but only if it came from panik) to retrieve an error value again which then can be returned to the caller. This compares to Java's checked exceptions (i.e. an exception which hints at a problem in the environment as opposed to a problem within the program) except that there is no mechanism for declaring this in a function's signature in Go.\n\n### panik by example\n\nMost commonly, you start a pani*k* with `panik.Panic()` (if the function you are in decides that there is an error right now) or `panik.OnError(err)` (if a function-call returned an error to you). You then later end the pani*k* with `defer panik.ToError(\u0026returnError)` (if you are at an API-boundary and don't want to give the caller some required reading) or one of the `defer panik.RecoverTrace...()` (if you are in some sort of worker) or `defer panik.ExitTrace...()` (if you are in `main()`) variants.\n\nPanics triggered through panik are special in that panik can tell them apart from panics triggered through `panic()`, such that a call of `defer panik.ToError(\u0026returnError)` will lastingly `recover()` and set `*returnError` only if the panic actually came from panik. This is accomplished with a package-private type which implements `error` as well as `Unwrap() error`. Basically, we make believe that a normal panic is a runtime exception while a \"panik\" is a checked exception.\n\n```go\n// doSomething(0) will return a nil error.\n// doSomething(1) will return a non-nil error with Error() == \"foo\".\n// doSomething(2) will panic.\nfunc doSomething(x int) (returnError error) {\n    defer panik.ToError(\u0026returnError)\n    doItNow(x)\n    return nil\n}\n\nfunc doItNow(x int) {\n    if x == 1 {\n        panik.Panic(\"foo\")\n    } else if x == 2 {\n        panic(\"foo\")\n    }\n}\n```\n\n```go\n// writeSomething(\"foo\") will panic with a `ToError()`-deescalatable error if err is non-nil.\nfunc writeSomething(filePath string) {\n    err := ioutil.WriteFile(filePath, \"Hello World!\", 0660)\n    panik.OnError(err)\n}\n```\n\n### additional shenanigans\n\n* You can use `defer panik.ToErrorWithTrace()` if your code is standalone and you really don't mind producing extra log output.\n* You can use `defer panik.Wrap`(`f`)`()` to add extra information to an ongoing panic.\n  * You will want to avoid calling this on a hot code path, since even if there is no panic, you are still making a function call with all of its arguments.\n  * Using these functions violates point 2 as laid out in [The problem](#the-problem), so keep an eye out for whether panik is even appropriate for what you are doing.\n\n## Remarks\n\n* If calling `recover()` yourself, you can differ between panics and paniks using `panik.Caused(r)`.\n  * You can always avoid having to do this by using `panik.ToError()` in the called function and then recovering in the caller normally.\n* You will still need to think about when to wrap an error and when to merely format its message; the types of wrapped errors are part of your API contract. See `OnErrorfv()` if you have an error you want to report to the caller but do not want to wrap.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsetlog%2Fpanik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsetlog%2Fpanik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsetlog%2Fpanik/lists"}