ipfs/kubo · error
could not read migration config: %w
Error message
could not read migration config: %w
What it means
When migration binaries aren't available locally and the code falls back to network download, it reads the migration config file via ReadMigrationConfig. A failure reading/parsing that config aborts with this wrapped error.
Source
Thrown at repo/fsrepo/migrations/migrations.go:399
return fmt.Errorf("could not determine migration paths: %w", err)
}
foundAll := true
for _, migName := range migrations {
if _, exists := binPaths[migName]; !exists {
foundAll = false
break
}
}
if foundAll {
return runMigrationsFromPath(ctx, migrations, binPaths, ipfsDir, logger, false)
}
// Fall back to network download (original behavior)
migrationCfg, err := ReadMigrationConfig(ipfsDir, "")
if err != nil {
return fmt.Errorf("could not read migration config: %w", err)
}
// Use existing RunMigration which handles network downloads properly (HTTPS only for legacy migrations)
fetcher, err := GetMigrationFetcher(migrationCfg.DownloadSources, GetDistPathEnv(CurrentIpfsDist), nil)
if err != nil {
return fmt.Errorf("failed to get migration fetcher: %w", err)
}
defer fetcher.Close()
return RunMigration(ctx, fetcher, targetVer, ipfsDir, allowDowngrade)
}
// Case 3: Hybrid migration (current < 16, target ≥ 16)
if needsExternal && needsEmbedded {
logger.Printf("Starting hybrid migration from version %d to %d", currentVer, targetVer)
logger.Print("Using hybrid migration strategy: external to v16, then embedded")
// Phase 1: Use external migrations to get to v16
logger.Printf("Phase 1: External migration from v%d to v%d", currentVer, embeddedMigrationsMinVersion)View on GitHub (pinned to 329838acdf)
Solutions
- Inspect and fix the migrations config file in IPFS_PATH (correct syntax, readable permissions)
- Delete the custom migration config to fall back to defaults (dist.ipfs.tech)
- Check file ownership: match the user running the daemon
- Test parsing manually by re-creating the config from the documented format
Example fix
// before
{"DownloadSources": ["https://dist.ipfs.tech",]} // trailing comma: parse error
// after
{"DownloadSources": ["https://dist.ipfs.tech"]} Defensive patterns
Strategy: validation
Validate before calling
cfgPath := filepath.Join(ipfsDir, "migrations")
if data, err := os.ReadFile(cfgPath); err == nil {
var cfg map[string]json.RawMessage
if err := json.Unmarshal(data, &cfg); err != nil {
log.Fatalf("invalid migration config %s: %v", cfgPath, err)
}
} Try / catch
if err != nil && strings.Contains(err.Error(), "could not read migration config") {
return fmt.Errorf("fix or delete the migrations config file in IPFS_PATH: %w", err)
} Prevention
- Validate the migrations config JSON after hand-editing
- Match file ownership with the daemon user
- Remove custom config to fall back to defaults
- Keep config minimal — only override what you need
When it happens
Trigger: ReadMigrationConfig(ipfsDir, "") fails because the migrations config file exists but is unreadable or malformed (invalid syntax), or an I/O error occurs reading it.
Common situations: Hand-edited migration config files with syntax errors; wrong permissions on the config file; config created by a different user (root) than the daemon user.
Related errors
- source field %s does not exist
- cannot get migrations from unknown fetcher type
- nothing downloaded by ipfs fetcher
- no local swarm address for migration node
- could not connect to migration peer %q: %s
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/1cafda2bdec84a86.
Report an issue: GitHub.