概要
AstroとCloudflare D1(Wrangler v3)を組み合わせた開発環境において、ローカルデータベース(.wrangler/state/v3/d1/)のキャッシュ破損により「no such table」などのエラーが頻発する問題に遭遇しました。
本記事では、不整合を起こしたローカル環境を安全に初期化し、既存のSQLiteファイル(local.db)からCloudflare D1の厳格な仕様に適合するようデータを浄化・復元する「正攻法」のスクリプトと手順を解説します。
避けるべきアンチパターン
復旧作業にあたり、以下の手法はデータベースの破損(WALファイルの不整合など)や、将来的なアップデートでの動作不良を招くため推奨されません。
- Miniflareの旧バージョンへのダウングレード
最新のWrangler(
workerdランタイム)の標準仕様から逸脱するため、本番環境との差異が生じます。 - キャッシュディレクトリへの直接上書き
.wrangler/state/v3/d1/配下に生成されるシステムファイルに、手元のlocal.dbを直接コピー・上書きする行為はデータベースの破損を引き起こします。
解決策:正規コマンドを用いた完全再構築
Wranglerの標準コマンド(migrations apply や execute)のみを使用し、以下の手順で復旧を行います。
- 破損したステート(キャッシュ)の完全削除
- スキーマ(設計図)の再適用
- 既存データからのSQLダンプ抽出
- Cloudflare D1非互換コマンドの除去(浄化処理)
- 浄化済みデータのインポート
Cloudflare D1におけるデータインポートの罠
SQLite標準の .dump コマンドで抽出したデータには、PRAGMA(外部キー制約の設定など)や、内部カウンターを操作する sqlite_sequence へのアクセスが含まれます。
しかし、Cloudflare D1はセキュリティ上の理由からこれらのシステム設定や内部テーブルへの直接操作を禁止しており、そのままインポートすると not authorized や object 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のサニタイズ処理が不可欠となります。