Troubleshooting - RumenDamyanov/go-chess GitHub Wiki

Troubleshooting

Common issues and solutions when working with the go-chess library.

Table of Contents

Installation Issues

Module Not Found

Problem: go get fails with module not found error

go: module github.com/rumendamyanov/go-chess not found

Solution:

# Ensure you have Go 1.21 or later
go version

# Initialize your module first
go mod init your-project-name
go get github.com/rumendamyanov/go-chess

# If still failing, try with specific version
go get github.com/rumendamyanov/go-chess@latest

Import Path Issues

Problem: Import paths not resolving correctly

// Wrong
import "go-chess/engine"

// Correct
import "github.com/rumendamyanov/go-chess/engine"

Solution: Always use the full import path.

Dependency Conflicts

Problem: Conflicting dependency versions

go: github.com/gin-gonic/gin v1.9.1 requires github.com/something incompatible

Solution:

# Clean module cache
go clean -modcache

# Update dependencies
go mod tidy
go mod download

# Force specific versions if needed
go mod edit -require github.com/gin-gonic/[email protected]

Runtime Errors

Invalid Move Errors

Problem: Moves are being rejected as invalid

move, err := game.ParseMove("e5") // Error: invalid move

Solutions:

// 1. Check if it's your turn
if game.CurrentPlayer() != engine.White {
    log.Println("Not white's turn")
}

// 2. Use full notation when ambiguous
move, err := game.ParseMove("e2e4") // More explicit

// 3. Check legal moves first
legalMoves := game.LegalMoves()
for _, legal := range legalMoves {
    if legal.String() == "e2e4" {
        // Move is legal
    }
}

// 4. Validate move before attempting
if game.IsLegalMove(move) {
    game.MakeMove(move)
}

Game State Errors

Problem: Game state inconsistencies

// Error: game already over
err := game.MakeMove(move)

Solutions:

// Always check game status
switch game.Status() {
case engine.StatusInProgress:
    // Game is ongoing, can make moves
case engine.StatusCheckmate:
    log.Printf("%s wins by checkmate", game.Winner())
case engine.StatusStalemate:
    log.Println("Game drawn by stalemate")
case engine.StatusDraw:
    log.Println("Game drawn")
default:
    log.Println("Cannot make moves, game is over")
}

Memory Issues

Problem: High memory usage or memory leaks

Solutions:

// 1. Properly dispose of games
func processGame() {
    game := engine.NewGame()
    defer game.Close() // If available

    // Use game...
}

// 2. Limit game history
game.SetMaxHistorySize(100) // Limit move history

// 3. Use object pooling for high-volume scenarios
var gamePool = sync.Pool{
    New: func() interface{} {
        return engine.NewGame()
    },
}

func usePooledGame() {
    game := gamePool.Get().(*engine.Game)
    defer gamePool.Put(game)

    game.Reset() // Reset to initial state
    // Use game...
}

AI Problems

AI Not Responding

Problem: AI hangs or doesn't return moves

ctx := context.Background()
move, err := ai.GetBestMove(ctx, game) // Hangs forever

Solutions:

// 1. Use context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

move, err := ai.GetBestMove(ctx, game)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        log.Println("AI timeout, using random move")
        // Fallback to quick move
    }
}

// 2. Set AI thinking time limits
aiPlayer := ai.NewMinimaxAI(ai.DifficultyMedium)
aiPlayer.SetMaxThinkTime(5 * time.Second)

// 3. Use simpler AI for testing
randomAI := ai.NewRandomAI() // Always fast

Poor AI Performance

Problem: AI makes obviously bad moves

Solutions:

// 1. Increase difficulty
aiPlayer.SetDifficulty(ai.DifficultyHard)

// 2. Use better AI engine
minima7AI := ai.NewMinimaxAI(ai.DifficultyHard)
// instead of
randomAI := ai.NewRandomAI()

// 3. Allow more thinking time
aiPlayer.SetMaxThinkTime(10 * time.Second)

// 4. Enable AI caching
aiPlayer.EnablePositionCache(true)

AI Crashes

Problem: AI engines panic or crash

defer func() {
    if r := recover(); r != nil {
        log.Printf("AI panic recovered: %v", r)
        // Use fallback AI
    }
}()

move, err := aiPlayer.GetBestMove(ctx, game)

LLM AI Issues

API Key Problems

Problem: Authentication failures with LLM providers

Error: 401 Unauthorized - Invalid API key

Solutions:

# 1. Check API key format
export OPENAI_API_KEY="sk-your-full-key-here"  # Must start with sk-

# 2. Verify key is active
curl -H "Authorization: Bearer $OPENAI_API_KEY" \
  https://api.openai.com/v1/models

# 3. Check key permissions
# Some keys may be restricted to specific models or usage patterns

Rate Limiting

Problem: Too many requests error

Error: 429 Too Many Requests - Rate limit exceeded

Solutions:

// 1. Implement rate limiting
import "golang.org/x/time/rate"

limiter := rate.NewLimiter(rate.Every(time.Second), 1) // 1 request per second

func callLLM() error {
    if err := limiter.Wait(context.Background()); err != nil {
        return err
    }

    // Make LLM call
    return llmAI.GetBestMove(ctx, game)
}

// 2. Implement exponential backoff
func callLLMWithBackoff() error {
    backoff := time.Second
    maxBackoff := time.Minute

    for attempts := 0; attempts < 5; attempts++ {
        err := llmAI.GetBestMove(ctx, game)
        if err == nil {
            return nil
        }

        if strings.Contains(err.Error(), "rate limit") {
            time.Sleep(backoff)
            backoff = time.Duration(float64(backoff) * 1.5)
            if backoff > maxBackoff {
                backoff = maxBackoff
            }
            continue
        }

        return err // Non-rate-limit error
    }

    return fmt.Errorf("max retries exceeded")
}

Model Errors

Problem: Model not found or deprecated

Error: Model 'gpt-3.5-turbo-old' not found

Solutions:

// Update to current model names
config := ai.LLMConfig{
    Provider: ai.ProviderOpenAI,
    Model:    "gpt-4o",  // Use latest model
    // Model:    "gpt-3.5-turbo", // Fallback option
}

// Check provider documentation for current models
// OpenAI: https://platform.openai.com/docs/models
// Anthropic: https://docs.anthropic.com/claude/docs/models-overview

Network Timeouts

Problem: LLM requests timing out

Solutions:

// 1. Increase timeout
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

// 2. Configure HTTP client with longer timeout
httpClient := &http.Client{
    Timeout: 120 * time.Second,
}

config := ai.LLMConfig{
    HTTPClient: httpClient,
}

// 3. Implement fallback
move, err := llmAI.GetBestMove(ctx, game)
if err != nil {
    log.Printf("LLM timeout: %v", err)
    // Fall back to traditional AI
    fallbackAI := ai.NewRandomAI()
    move, err = fallbackAI.GetBestMove(ctx, game)
}

API Server Issues

Port Already in Use

Problem: Server fails to start

Error: listen tcp :8080: bind: address already in use

Solutions:

# 1. Find what's using the port
lsof -i :8080
# or
netstat -an | grep 8080

# 2. Kill the process
sudo kill -9 <PID>

# 3. Use a different port
export CHESS_PORT=8081
# or modify config
// In code
cfg.Server.Port = 8081

CORS Issues

Problem: Frontend can't access API

Error: CORS policy blocked request

Solutions:

// 1. Enable CORS in server setup
r.Use(func(c *gin.Context) {
    c.Header("Access-Control-Allow-Origin", "*")
    c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
    c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")

    if c.Request.Method == "OPTIONS" {
        c.AbortWithStatus(204)
        return
    }

    c.Next()
})

// 2. Use cors middleware
import "github.com/gin-contrib/cors"

config := cors.DefaultConfig()
config.AllowAllOrigins = true
r.Use(cors.New(config))

JSON Parsing Errors

Problem: Invalid JSON in requests

Error: invalid character '}' looking for beginning of value

Solutions:

// 1. Validate JSON before processing
var req struct {
    From string `json:"from"`
    To   string `json:"to"`
}

if err := c.ShouldBindJSON(&req); err != nil {
    c.JSON(400, gin.H{"error": "Invalid JSON: " + err.Error()})
    return
}

// 2. Provide better error messages
if req.From == "" || req.To == "" {
    c.JSON(400, gin.H{"error": "Missing required fields: from, to"})
    return
}

Database Connection Issues

Problem: If using database for game persistence

Error: failed to connect to database

Solutions:

// 1. Connection retry logic
func connectWithRetry() (*sql.DB, error) {
    var db *sql.DB
    var err error

    for attempts := 0; attempts < 5; attempts++ {
        db, err = sql.Open("postgres", connectionString)
        if err == nil {
            if err = db.Ping(); err == nil {
                return db, nil
            }
        }

        log.Printf("Database connection attempt %d failed: %v", attempts+1, err)
        time.Sleep(time.Duration(attempts+1) * time.Second)
    }

    return nil, fmt.Errorf("failed to connect after 5 attempts: %w", err)
}

// 2. Connection pooling
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)

Performance Problems

Slow Move Generation

Problem: AI takes too long to generate moves

Solutions:

// 1. Reduce AI depth
aiPlayer := ai.NewMinimaxAI(ai.DifficultyMedium) // Instead of Expert

// 2. Set time limits
aiPlayer.SetMaxThinkTime(3 * time.Second)

// 3. Use faster algorithms for real-time play
quickAI := ai.NewRandomAI() // For very fast responses

// 4. Enable caching
aiPlayer.EnablePositionCache(true)
aiPlayer.SetCacheSize(10000)

Memory Usage

Problem: High memory consumption

Solutions:

// 1. Limit game history
game.SetMaxMoveHistory(100)

// 2. Use object pooling
var boardPool = sync.Pool{
    New: func() interface{} {
        return engine.NewBoard()
    },
}

// 3. Regular garbage collection
import "runtime"

go func() {
    for {
        time.Sleep(30 * time.Second)
        runtime.GC()
    }
}()

// 4. Profile memory usage
import _ "net/http/pprof"

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// Then visit http://localhost:6060/debug/pprof/

CPU Usage

Problem: High CPU utilization

Solutions:

// 1. Limit concurrent AI calculations
semaphore := make(chan struct{}, 2) // Max 2 concurrent AI operations

func getAIMove() error {
    semaphore <- struct{}{} // Acquire
    defer func() { <-semaphore }() // Release

    return aiPlayer.GetBestMove(ctx, game)
}

// 2. Use worker pools
type aiJob struct {
    game   *engine.Game
    result chan aiResult
}

type aiResult struct {
    move engine.Move
    err  error
}

func aiWorker(jobs <-chan aiJob) {
    for job := range jobs {
        move, err := aiPlayer.GetBestMove(context.Background(), job.game)
        job.result <- aiResult{move, err}
    }
}

Configuration Issues

Invalid Configuration

Problem: Configuration file errors

Error: failed to parse config.json

Solutions:

# 1. Validate JSON syntax
cat config.json | jq . # Validates JSON

# 2. Check file permissions
ls -la config.json
chmod 644 config.json

# 3. Use configuration validation
func validateConfig(cfg *config.Config) error {
    if cfg.Server.Port < 1024 || cfg.Server.Port > 65535 {
        return fmt.Errorf("invalid port: %d", cfg.Server.Port)
    }

    if cfg.LLMAI.Enabled {
        for name, provider := range cfg.LLMAI.Providers {
            if provider.APIKey == "" {
                return fmt.Errorf("missing API key for provider: %s", name)
            }
        }
    }

    return nil
}

Environment Variables

Problem: Environment variables not being read

export CHESS_PORT=8080  # Not taking effect

Solutions:

# 1. Check if variable is set
echo $CHESS_PORT

# 2. Use env command to verify
env | grep CHESS

# 3. Check variable in Go
port := os.Getenv("CHESS_PORT")
if port == "" {
    log.Println("CHESS_PORT not set, using default")
}

Development Issues

Build Errors

Problem: Compilation failures

./main.go:10:2: no required module provides package github.com/rumendamyanov/go-chess/engine

Solutions:

# 1. Ensure module is properly initialized
go mod init your-project
go mod tidy

# 2. Check Go version
go version # Should be 1.21+

# 3. Clear module cache if corrupted
go clean -modcache

Test Failures

Problem: Tests failing unexpectedly

go test ./...
FAIL: TestMakeMove (0.00s)

Solutions:

# 1. Run tests with verbose output
go test -v ./...

# 2. Run specific test
go test -v -run TestMakeMove

# 3. Check for race conditions
go test -race ./...

# 4. Clean test cache
go clean -testcache

Import Cycles

Problem: Circular import dependencies

package command-line-arguments
    imports A
    imports B
    imports A: import cycle not allowed

Solutions:

// 1. Move shared code to separate package
// Create shared/common package for shared types

// 2. Use interfaces to break cycles
type GameInterface interface {
    MakeMove(move Move) error
    LegalMoves() []Move
}

// 3. Restructure packages to avoid cycles

Getting Help

Debug Information

When reporting issues, include:

func collectDebugInfo() map[string]interface{} {
    return map[string]interface{}{
        "go_version":    runtime.Version(),
        "os":           runtime.GOOS,
        "arch":         runtime.GOARCH,
        "game_fen":     game.FEN(),
        "last_moves":   game.MoveHistory(),
        "ai_config":    aiPlayer.GetConfig(),
        "error_trace":  string(debug.Stack()),
    }
}

Community Resources

Professional Support

For production issues or custom development:

  • Create detailed issue reports with reproduction steps
  • Include debug information and logs
  • Consider contributing fixes back to the project

Remember: Most issues are configuration or usage related. Double-check the documentation and examples before diving deep into debugging!

⚠️ **GitHub.com Fallback** ⚠️