gofr-dev/gofr · error

unexpected error stating migration file: %w

Error message

unexpected error stating migration file: %w

What it means

Returned by checkAndCreateMigrationTable when os.Stat on the migration file fails with an error other than 'not exists' — e.g. permission denied on the path or an I/O error. The migrator can neither read nor safely create the file, so it aborts. Note the message's likely typo ('stating' for 'stat-ing').

Source

Thrown at pkg/gofr/migration/opentsdb.go:66

func (om *openTSDBMigrator) checkAndCreateMigrationTable(c *container.Container) error {
	om.mu.Lock()
	defer om.mu.Unlock()

	// Ensure directory exists
	dir := filepath.Dir(om.filePath)
	if dir != "." {
		if err := os.MkdirAll(dir, dirPerm); err != nil {
			return fmt.Errorf("failed to create migration directory %q: %w", dir, err)
		}
	}

	// Check if file exists and is readable
	if _, err := os.Stat(om.filePath); err == nil {
		// File exists, validate it's proper JSON
		return om.validateExistingFile(c)
	} else if !os.IsNotExist(err) {
		// Some other error accessing the file
		return fmt.Errorf("unexpected error stating migration file: %w", err)
	}

	// File doesn't exist, create empty migration file
	return om.createEmptyMigrationFile(c)
}

// validateExistingFile checks if the existing migration file is valid JSON.
func (om *openTSDBMigrator) validateExistingFile(c *container.Container) error {
	file, err := os.Open(om.filePath)
	if err != nil {
		return fmt.Errorf("failed to open existing migration file: %w", err)
	}
	defer file.Close()

	var migrations []tsdbMigrationRecord
	if err = json.NewDecoder(file).Decode(&migrations); err != nil {
		c.Errorf("Existing migration file is corrupted: %v", err)
		return fmt.Errorf("existing migration file contains invalid JSON: %w", err)

View on GitHub (pinned to 187eb24962)

Solutions

  1. Read the wrapped OS errno to identify the stat failure
  2. Fix permissions on the file and its parent directories (0755 dir, owner write)
  3. Replace broken symlinks and verify the mount is healthy
  4. Adjust SELinux/AppArmor policies if they block stat on the path

Example fix

// before
ls -l /data/gofr_migrations.json // owned by root, app runs as appuser -> stat EACCES
// after
chown appuser:appuser /data/gofr_migrations.json && chmod 644 /data/gofr_migrations.json
Defensive patterns

Strategy: validation

Validate before calling

p := cfg.OpenTSDBMigrationFile
if _, err := os.Stat(p); err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("migration file path has access problems (check perms/symlink): %w", err)
}
if info, err := os.Lstat(p); err == nil && info.Mode()&os.ModeSymlink != 0 {
    return errors.New("migration file is a symlink; verify target")
}

Prevention

When it happens

Trigger: os.Stat(om.filePath) errors with something other than os.IsNotExist: EACCES on a parent directory, ELOOP from symlink cycles, or device-level I/O errors.

Common situations: Wrong ownership/permissions on the migration file's directory; broken symlink loop at the path; failing disk or detached mount; overly restrictive security contexts (SELinux/AppArmor).

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/f4b05b53b5b1b870. Report an issue: GitHub.