AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Go Error Management

skill-v0lka-skills-go-error-management · by v0lka

>

No reviews yet
0 installs
34 views
0.0% view→install

Install

$ agentstack add skill-v0lka-skills-go-error-management

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution Used

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-v0lka-skills-go-error-management)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Go Error Management? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Go Error Management

Rules and patterns for idiomatic Go error handling based on common mistakes #48-#54.


1. Panicking (#48)

Rule: Reserve panic for truly unrecoverable conditions only. Never use panic as a substitute for returning errors.

Acceptable uses of panic:

  • Programmer errors (invariant violations that indicate a bug)
  • Failure to initialize a mandatory dependency during startup (e.g., regexp.MustCompile for a required regex)

Never panic for:

  • User input validation
  • Network/IO failures
  • Any condition the caller could reasonably handle
// GOOD: panic for programmer error (invalid invariant)
func MustCompileSchema(pattern string) *regexp.Regexp {
    re, err := regexp.Compile(pattern)
    if err != nil {
        panic(fmt.Sprintf("invalid regex pattern: %s", err))
    }
    return re
}

// BAD: panicking on a runtime error the caller should handle
func GetUser(id string) User {
    u, err := db.FindUser(id)
    if err != nil {
        panic(err) // DO NOT do this
    }
    return u
}

2. Error Wrapping vs Transforming (#49)

Rule: Choose deliberately between wrapping (%w), transforming (%v), and returning directly based on whether the caller should access the source error.

| Technique | Extra context | Source error available | Creates coupling | |---|---|---|---| | return err | No | Yes | No | | fmt.Errorf("...: %w", err) | Yes | Yes (unwrappable) | Yes | | fmt.Errorf("...: %v", err) | Yes | No | No | | Custom error type wrapping | Yes | Yes | Yes |

Guidelines:

  • Wrap (%w) when the caller legitimately needs to inspect the source error (e.g., checking for sql.ErrNoRows).
  • Transform (%v) when the source error is an implementation detail the caller should not depend on.
  • Return directly when no additional context is needed and the error is already descriptive.
  • Default to %w within a package. Use %v at API boundaries where you want to hide internals.
// Wrapping: caller can inspect the source error
return fmt.Errorf("failed to get transaction %s: %w", id, err)

// Transforming: hides implementation detail
return fmt.Errorf("failed to get transaction %s: %v", id, err)

// Direct return: error is already descriptive enough
return err

3. Checking Error Types with errors.As (#50)

Rule: Never use type assertion or type switch to check error types. Always use errors.As, which unwraps the error chain.

A type switch (switch err.(type)) only matches the outermost error. If the target error type is wrapped inside another error via %w, the match silently fails.

// BAD: breaks if transientError is wrapped
switch err := err.(type) {
case transientError:
    // This won't match a wrapped transientError
}

// GOOD: works regardless of wrapping depth
var te transientError
if errors.As(err, &te) {
    // te is populated with the matched error
    http.Error(w, te.Error(), http.StatusServiceUnavailable)
} else {
    http.Error(w, err.Error(), http.StatusBadRequest)
}

Important: The second argument to errors.As must be a pointer to the target type. Passing a non-pointer compiles but panics at runtime.


4. Checking Error Values with errors.Is (#51)

Rule: Never use == to compare errors against sentinel values. Always use errors.Is, which traverses the entire wrapped error chain.

// BAD: breaks if sql.ErrNoRows is wrapped
if err == sql.ErrNoRows {
    // ...
}

// GOOD: works through any wrapping depth
if errors.Is(err, sql.ErrNoRows) {
    // ...
}

Design guideline for sentinel errors:

  • Expected errors (caller is meant to check for them) -> sentinel values: var ErrNotFound = errors.New("not found")
  • Unexpected errors (structural/contextual info needed) -> custom error types: type ValidationError struct{ ... }

5. Handle an Error Exactly Once (#52)

Rule: An error must be handled exactly once. Logging an error counts as handling it. Returning an error counts as handling it. Never do both.

// BAD: handles the error twice (logs AND returns)
func GetRoute(srcLat, srcLng, dstLat, dstLng float32) (Route, error) {
    err := validateCoordinates(srcLat, srcLng)
    if err != nil {
        log.Println("failed to validate source coordinates")
        return Route{}, err // logged AND returned
    }
    // ...
}

// GOOD: handles the error once (wraps and returns, no log)
func GetRoute(srcLat, srcLng, dstLat, dstLng float32) (Route, error) {
    err := validateCoordinates(srcLat, srcLng)
    if err != nil {
        return Route{}, fmt.Errorf("failed to validate source coords: %w", err)
    }
    // ...
}

Consequences of double-handling:

  • Duplicate/interleaved log lines in concurrent code make debugging harder.
  • Context is split across log and error message, neither is complete.

Pattern: Return errors with added context (%w); let the top-level caller (HTTP handler, main, etc.) log once.


6. Explicitly Ignore Errors (#53)

Rule: When intentionally ignoring an error, assign it to the blank identifier _. Never silently discard by omitting assignment.

// BAD: unclear if the developer forgot to handle the error
notify()

// GOOD: explicit that error is intentionally ignored
_ = notify()

// BETTER: explain WHY the error is ignored
// At-most-once delivery; acceptable to miss some notifications on error.
_ = notify()

Do not add comments like // Ignore the error -- that just restates the code. Instead explain the rationale for ignoring.


7. Handling Defer Errors (#54)

Rule: Never silently discard errors from defer calls. At minimum, explicitly ignore them. Prefer logging or propagating.

Option A: Log the defer error

defer func() {
    if err := rows.Close(); err != nil {
        log.Printf("failed to close rows: %v", err)
    }
}()

Option B: Propagate using named return parameters

When both the main body and the defer can fail, prioritize the original error:

func getBalance(db *sql.DB, clientID string) (balance float32, err error) {
    rows, err := db.Query(query, clientID)
    if err != nil {
        return 0, err
    }
    defer func() {
        closeErr := rows.Close()
        if err != nil {
            // Body already failed; log the close error, keep the original.
            if closeErr != nil {
                log.Printf("failed to close rows: %v", closeErr)
            }
            return
        }
        // Body succeeded; surface the close error.
        err = closeErr
    }()

    if rows.Next() {
        if err := rows.Scan(&balance); err != nil {
            return 0, err
        }
        return balance, nil
    }
    // ...
}

Option C: Explicitly ignore (when truly acceptable)

defer func() { _ = rows.Close() }()

Never write bare defer rows.Close() when Close() returns an error -- it silently discards the error with no indication of intent.


Quick Reference

| Mistake | Rule | |---|---| | #48 Panicking | Only for programmer errors or mandatory-dependency init failures | | #49 Wrapping | %w = caller can unwrap; %v = opaque transform; choose intentionally | | #50 Error type check | Use errors.As, never type switch/assertion | | #51 Error value check | Use errors.Is, never == | | #52 Double handling | Either log or return, never both; wrap with %w for context | | #53 Ignoring errors | Assign to _; comment the rationale, not the action | | #54 Defer errors | Log, propagate via named returns, or explicitly ignore -- never bare defer |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.