Skip to content

nightshift: error-msg-improve audit #40

Description

@nightshift-micr

nightshift: Error Message Improvement Audit

Repository: Microck/tailstick
Task: error-msg-improve
Category: options
Date: 2026-04-23


Summary

Audited all error messages across the Go codebase (8 packages, ~2000 lines of source). Found 50+ error creation sites. Good error wrapping in config and tailscale packages, but bare error propagation in crypto, state, and logging.

Findings by Package

internal/crypto/secret.go — 15 bare return err with no context

Severity: 🟡 MEDIUM

Encrypt() and Decrypt() have 15 return "", err statements with zero context. When encryption/decryption fails, the operator sees only the Go stdlib error (e.g., "crypto/cipher: invalid key size") with no indication it came from tailstick's secret handling.

Recommendation: Wrap each error site:

return "", fmt.Errorf("derive key: %w", err)
return "", fmt.Errorf("create cipher: %w", err)
return "", fmt.Errorf("generate nonce: %w", err)
return "", fmt.Errorf("marshal envelope: %w", err)

internal/state/store.go — 7 bare return err with no context

Severity: 🟡 MEDIUM

Only 2 sites have context ("read state", "parse state"). The other 7 return bare errors. State corruption issues are hard to diagnose without knowing which table/operation failed.

Recommendation: Wrap all error returns with operation context:

return fmt.Errorf("marshal state: %w", err)
return fmt.Errorf("write state file %s: %w", s.path, err)

internal/app/workflow.go — ~12 bare error returns

Severity: 🟡 MEDIUM

The Enroll function alone has ~10 error sites, most returning bare err. Enrollment is the primary user flow — errors need step context.

Recommendation: Wrap errors with the enrollment step that failed:

return model.LeaseRecord{}, fmt.Errorf("load config: %w", err)
return model.LeaseRecord{}, fmt.Errorf("resolve preset: %w", err)
return model.LeaseRecord{}, fmt.Errorf("validate lease duration: %w", err)

internal/logging/logger.go — 3 bare return err

Severity: 🟢 LOW

Recommendation: Add context: return nil, fmt.Errorf("create log directory: %w", err), etc.

internal/tailscale/client.go — Mostly good, 2 minor improvements

Severity: 🟢 LOW

Good messages (context included):

  • "no install command configured for platform %s"
  • "stable channel requires configured stable version"
  • "session mode requires ephemeral auth key"
  • "missing auth key"

Could improve:

  • Line 119: "status json missing Self object""parse tailscale status: response JSON missing required Self object"
  • Line 258: "timed lease requires days in {1,3,7}..." → include the actual invalid value: "...got %d"

internal/config/config.go — Excellent error messages ✅

All errors are descriptive and include context. No changes needed.

Error Message Quality Scorecard

Package Total Sites Wrapped Bare Score
config 7 7 0 ⭐⭐⭐⭐⭐
tailscale 20 14 6 ⭐⭐⭐⭐
gui 3 2 1 ⭐⭐⭐⭐
app/workflow ~15 ~3 ~12 ⭐⭐
state 9 2 7 ⭐⭐
crypto 15 1 14
logging 3 0 3

Recommended Priority

  1. crypto/secret.go — 15 bare returns, most impactful for debugging secret handling failures
  2. state/store.go — 7 bare returns, state corruption hard to diagnose without context
  3. app/workflow.go — Enrollment is the primary user flow; errors need step context
  4. logging/logger.go — 3 bare returns, low priority
  5. tailscale/client.go — Minor improvements to 2 existing messages

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions