// internal/errors/basic.gopackageerrorsimport("errors""fmt""io""os")// Basic error handlingfuncReadFile(filenamestring)([]byte,error){file,err:=os.Open(filename)iferr!=nil{returnnil,fmt.Errorf("failed to open file %s: %w",filename,err)}deferfile.Close()data,err:=io.ReadAll(file)iferr!=nil{returnnil,fmt.Errorf("failed to read file %s: %w",filename,err)}returndata,nil}// Error checking with early returnfuncProcessData(data[]byte)error{iflen(data)==0{returnerrors.New("data cannot be empty")}iflen(data)>1024*1024{returnfmt.Errorf("data too large: %d bytes",len(data))}// Process data...returnnil}
// internal/errors/wrapping.gopackageerrorsimport("errors""fmt""io")// WrapError wraps an error with additional contextfuncWrapError(errerror,messagestring)error{iferr==nil{returnnil}returnfmt.Errorf("%s: %w",message,err)}// WrapErrorf wraps an error with formatted contextfuncWrapErrorf(errerror,formatstring,args...interface{})error{iferr==nil{returnnil}returnfmt.Errorf("%s: %w",fmt.Sprintf(format,args...),err)}// IsError checks if the error chain contains a specific errorfuncIsError(err,targeterror)bool{returnerrors.Is(err,target)}// AsError extracts a specific error type from the error chainfuncAsError(errerror,targetinterface{})bool{returnerrors.As(err,target)}// Example usagefuncProcessFile(filenamestring)error{data,err:=ReadFile(filename)iferr!=nil{returnWrapErrorf(err,"failed to process file %s",filename)}iferr:=ProcessData(data);err!=nil{returnWrapError(err,"data processing failed")}returnnil}
// internal/errors/custom.gopackageerrorsimport("fmt""time")// ErrorCode represents different types of errorstypeErrorCodeintconst(ErrorCodeValidationErrorCode=iotaErrorCodeNotFoundErrorCodeUnauthorizedErrorCodeInternalErrorCodeTimeoutErrorCodeRateLimit)// AppError represents an application errortypeAppErrorstruct{CodeErrorCodeMessagestringDetailsmap[string]interface{}Timestamptime.TimeCauseerror}// Error implements the error interfacefunc(ae*AppError)Error()string{ifae.Cause!=nil{returnfmt.Sprintf("[%s] %s: %v",ae.Code.String(),ae.Message,ae.Cause)}returnfmt.Sprintf("[%s] %s",ae.Code.String(),ae.Message)}// Unwrap returns the underlying causefunc(ae*AppError)Unwrap()error{returnae.Cause}// String returns the string representation of the error codefunc(ecErrorCode)String()string{switchec{caseErrorCodeValidation:return"VALIDATION_ERROR"caseErrorCodeNotFound:return"NOT_FOUND"caseErrorCodeUnauthorized:return"UNAUTHORIZED"caseErrorCodeInternal:return"INTERNAL_ERROR"caseErrorCodeTimeout:return"TIMEOUT"caseErrorCodeRateLimit:return"RATE_LIMIT"default:return"UNKNOWN_ERROR"}}// NewAppError creates a new application errorfuncNewAppError(codeErrorCode,messagestring,causeerror)*AppError{return&AppError{Code:code,Message:message,Details:make(map[string]interface{}),Timestamp:time.Now(),Cause:cause,}}// WithDetail adds a detail to the errorfunc(ae*AppError)WithDetail(keystring,valueinterface{})*AppError{ae.Details[key]=valuereturnae}
// internal/errors/validation.gopackageerrorsimport("fmt""strings")// ValidationError represents a validation errortypeValidationErrorstruct{FieldstringValueinterface{}Messagestring}// Error implements the error interfacefunc(ve*ValidationError)Error()string{returnfmt.Sprintf("validation error for field '%s': %s",ve.Field,ve.Message)}// ValidationErrors represents multiple validation errorstypeValidationErrorsstruct{Errors[]ValidationError}// Error implements the error interfacefunc(ve*ValidationErrors)Error()string{iflen(ve.Errors)==0{return"no validation errors"}varmessages[]stringfor_,err:=rangeve.Errors{messages=append(messages,err.Error())}returnfmt.Sprintf("validation errors: %s",strings.Join(messages,"; "))}// Add adds a validation errorfunc(ve*ValidationErrors)Add(fieldstring,valueinterface{},messagestring){ve.Errors=append(ve.Errors,ValidationError{Field:field,Value:value,Message:message,})}// HasErrors returns true if there are validation errorsfunc(ve*ValidationErrors)HasErrors()bool{returnlen(ve.Errors)>0}// NewValidationError creates a new validation errorfuncNewValidationError(fieldstring,valueinterface{},messagestring)*ValidationError{return&ValidationError{Field:field,Value:value,Message:message,}}
// internal/errors/recovery.gopackageerrorsimport("fmt""log""runtime")// RecoverPanic recovers from a panic and returns an errorfuncRecoverPanic()error{ifr:=recover();r!=nil{returnfmt.Errorf("panic recovered: %v",r)}returnnil}// SafeExecute executes a function with panic recoveryfuncSafeExecute(fnfunc()error)(errerror){deferfunc(){ifr:=recover();r!=nil{err=fmt.Errorf("panic recovered: %v",r)}}()returnfn()}// LogPanic logs panic informationfuncLogPanic(){ifr:=recover();r!=nil{stack:=make([]byte,4096)length:=runtime.Stack(stack,false)log.Printf("panic recovered: %v\nstack trace:\n%s",r,stack[:length])}}// Example usagefuncProcessWithRecovery(datainterface{})error{deferLogPanic()// Risky operation that might panicreturnprocessData(data)}
// internal/errors/aggregation.gopackageerrorsimport("fmt""strings")// MultiError represents multiple errorstypeMultiErrorstruct{Errors[]error}// Error implements the error interfacefunc(me*MultiError)Error()string{iflen(me.Errors)==0{return"no errors"}varmessages[]stringfor_,err:=rangeme.Errors{messages=append(messages,err.Error())}returnfmt.Sprintf("multiple errors: %s",strings.Join(messages,"; "))}// Add adds an error to the collectionfunc(me*MultiError)Add(errerror){iferr!=nil{me.Errors=append(me.Errors,err)}}// HasErrors returns true if there are errorsfunc(me*MultiError)HasErrors()bool{returnlen(me.Errors)>0}// NewMultiError creates a new multi-errorfuncNewMultiError()*MultiError{return&MultiError{Errors:make([]error,0),}}
// internal/errors/context.gopackageerrorsimport("context""fmt""time")// ContextError represents an error with context informationtypeContextErrorstruct{OperationstringContextmap[string]interface{}Timestamptime.TimeCauseerror}// Error implements the error interfacefunc(ce*ContextError)Error()string{returnfmt.Sprintf("error in %s: %v",ce.Operation,ce.Cause)}// Unwrap returns the underlying causefunc(ce*ContextError)Unwrap()error{returnce.Cause}// WithContext creates an error with contextfuncWithContext(operationstring,errerror,contextmap[string]interface{})*ContextError{return&ContextError{Operation:operation,Context:context,Timestamp:time.Now(),Cause:err,}}// HandleContextError handles context cancellationfuncHandleContextError(ctxcontext.Context,operationstring)error{select{case<-ctx.Done():returnWithContext(operation,ctx.Err(),map[string]interface{}{"cancelled":true,"deadline":ctx.Deadline(),})default:returnnil}}
// internal/errors/metrics.gopackageerrorsimport("sync""time")// ErrorMetrics tracks error statisticstypeErrorMetricsstruct{musync.RWMutexerrorCountsmap[string]interrorRatesmap[string]float64lastResettime.Time}// NewErrorMetrics creates new error metricsfuncNewErrorMetrics()*ErrorMetrics{return&ErrorMetrics{errorCounts:make(map[string]int),errorRates:make(map[string]float64),lastReset:time.Now(),}}// RecordError records an error occurrencefunc(em*ErrorMetrics)RecordError(errorTypestring){em.mu.Lock()deferem.mu.Unlock()em.errorCounts[errorType]++}// GetErrorCount returns the count for an error typefunc(em*ErrorMetrics)GetErrorCount(errorTypestring)int{em.mu.RLock()deferem.mu.RUnlock()returnem.errorCounts[errorType]}// GetErrorRate returns the rate for an error typefunc(em*ErrorMetrics)GetErrorRate(errorTypestring)float64{em.mu.RLock()deferem.mu.RUnlock()returnem.errorRates[errorType]}// Reset resets the metricsfunc(em*ErrorMetrics)Reset(){em.mu.Lock()deferem.mu.Unlock()em.errorCounts=make(map[string]int)em.errorRates=make(map[string]float64)em.lastReset=time.Now()}
// ❌ Bad: Ignoring errorsfuncBadExample(){file,_:=os.Open("file.txt")// Don't ignore errorsdeferfile.Close()}// ❌ Bad: Generic error messagesfuncBadExample2()error{returnerrors.New("error")// Too generic}// ❌ Bad: Panic for control flowfuncBadExample3(){ifcondition{panic("something went wrong")// Don't use panic for control flow}}