プロフィール

arismmn timeline blog

← ブログ一覧に戻る

Cloudflare D1のローカルDBが破損した際の完全復旧手順

Cloudflareデータベースデバッグ

概要

AstroCloudflare D1(Wrangler v3)を組み合わせた開発環境において、ローカルデータベース(.wrangler/state/v3/d1/)のキャッシュ破損により「no such table」などのエラーが頻発する問題に遭遇しました。

本記事では、不整合を起こしたローカル環境を安全に初期化し、既存のSQLiteファイル(local.db)からCloudflare D1の厳格な仕様に適合するようデータを浄化・復元する「正攻法」のスクリプトと手順を解説します。

避けるべきアンチパターン

復旧作業にあたり、以下の手法はデータベースの破損(WALファイルの不整合など)や、将来的なアップデートでの動作不良を招くため推奨されません。

  1. Miniflareの旧バージョンへのダウングレード 最新のWrangler(workerdランタイム)の標準仕様から逸脱するため、本番環境との差異が生じます。
  2. キャッシュディレクトリへの直接上書き .wrangler/state/v3/d1/ 配下に生成されるシステムファイルに、手元の local.db を直接コピー・上書きする行為はデータベースの破損を引き起こします。

解決策:正規コマンドを用いた完全再構築

Wranglerの標準コマンド(migrations applyexecute)のみを使用し、以下の手順で復旧を行います。

  1. 破損したステート(キャッシュ)の完全削除
  2. スキーマ(設計図)の再適用
  3. 既存データからのSQLダンプ抽出
  4. Cloudflare D1非互換コマンドの除去(浄化処理)
  5. 浄化済みデータのインポート

Cloudflare D1におけるデータインポートの罠

SQLite標準の .dump コマンドで抽出したデータには、PRAGMA(外部キー制約の設定など)や、内部カウンターを操作する sqlite_sequence へのアクセスが含まれます。 しかし、Cloudflare D1はセキュリティ上の理由からこれらのシステム設定や内部テーブルへの直接操作を禁止しており、そのままインポートすると not authorizedobject name reserved for internal use といったエラーが発生します。

また、WindowsのPowerShellを使用して出力をリダイレクト(>Out-File)すると、文字コードの不整合(Shift-JISとしての誤解釈やBOMの付与)により、SQLの構文エラーが引き起こされる問題も確認しました。

完全自動化復旧スクリプト(PowerShell)

上記の問題をすべて解決したスクリプトが以下になります。プロジェクトルートディレクトリに配置して実行します。

# scripts/restore_local_d1.ps1
# 概要: ローカルD1環境を更地から再構築し、Cloudflare D1互換のクリーンなデータを復元する完全自動スクリプトです。
# 日時: 2026-02-25 19:40:00 (JST)

Write-Host "1. Cleaning up broken state..."
Remove-Item -Recurse -Force .wrangler\state\v3\d1 -ErrorAction SilentlyContinue

# 完全版の設計図を適用し、すべてのテーブルの土台を作ります
if (Test-Path "db/schema.sql") {
    Write-Host "2. Applying schema.sql (Complete Base Schema)..."
    # ※ <your-database-name> は wrangler.jsonc 等の設定に合わせて変更してください
    pnpm wrangler d1 execute <your-database-name> --local --file=db/schema.sql
} else {
    Write-Host "Error: schema.sql not found! Please check the file path."
    exit
}

# 既存データが存在するか確認し、データの抽出と完璧な浄化を行います
if (Test-Path "local.db") {
    Write-Host "3. local.db found. Checking for sqlite3..."
    if (Get-Command sqlite3 -ErrorAction SilentlyContinue) {
        Write-Host "   Extracting raw data using sqlite3..."
        
        # PowerShellのリダイレクトを使わず、sqlite3のネイティブ機能で書き出します
        sqlite3 local.db ".output seed.raw.sql" ".dump --data-only"
        
        Write-Host "   Sanitizing SQL for Cloudflare D1 compatibility..."
        $rawSqlPath = Join-Path (Get-Location) "seed.raw.sql"
        $cleanSqlPath = Join-Path (Get-Location) "seed.sql"
        
        $lines = [System.IO.File]::ReadAllLines($rawSqlPath)
        $validLines = [System.Collections.Generic.List[string]]::new()
        
        foreach ($line in $lines) {
            # D1でエラーとなる内部シーケンス操作を完全に除外
            if ($line -match 'sqlite_sequence') { continue }
            
            # D1が許可していないシステムコマンド群を除外
            if ($line -match '(?i)^PRAGMA') { continue }
            if ($line -match '(?i)^BEGIN') { continue }
            if ($line -match '(?i)^COMMIT') { continue }
            
            if ([string]::IsNullOrWhiteSpace($line)) { continue }
            
            $validLines.Add($line)
        }
        
        # 文字コード起因の構文エラーを防ぐため、BOMなしUTF-8で保存
        $utf8NoBom = New-Object System.Text.UTF8Encoding $false
        [System.IO.File]::WriteAllLines($cleanSqlPath, $validLines, $utf8NoBom)
        
        Write-Host "   Importing sanitized data to local D1..."
        pnpm wrangler d1 execute <your-database-name> --local --file=seed.sql
        
        # 一時ファイルの削除
        Remove-Item "seed.raw.sql" -ErrorAction SilentlyContinue
        
        Write-Host "Data restored successfully!"
    } else {
        Write-Host "   WARNING: sqlite3 command not found. Skipping data import."
    }
} else {
    Write-Host "3. local.db not found. Starting fresh with an empty database."
}

まとめ

Cloudflare D1のローカル開発環境で問題が発生した際は、内部ファイル(.wranglerディレクトリ内)を手動で操作するのではなく、一度キャッシュを破棄した上で、Wranglerの公式コマンドを使用してスキーマ構築とデータインポートをやり直すのが最も安全で確実な方法です。

特に既存データを移行する際は、D1の制限(PRAGMAや内部テーブルへのアクセス禁止)を考慮したSQLのサニタイズ処理が不可欠となります。

Gemini
Powered by
Gemini
← ブログ一覧に戻る