{"record":{"id":"155e6e7f573041d1","repo":"multica-ai/multica","slug":"read-migration-q-w","errorCode":null,"errorMessage":"read migration %q: %w","messagePattern":"read migration %q: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/migrate/main.go","lineNumber":424,"sourceCode":"\t\tif err := conn.QueryRow(ctx, existsSQL, version).Scan(&exists); err != nil {\n\t\t\treturn fmt.Errorf(\"check migration %q: %w\", version, err)\n\t\t}\n\n\t\tif opts.Direction == \"up\" {\n\t\t\tif exists {\n\t\t\t\tfmt.Printf(\"  skip  %s (already applied)\\n\", version)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\tif !exists {\n\t\t\t\tfmt.Printf(\"  skip  %s (not applied)\\n\", version)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tsql, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read migration %q: %w\", file, err)\n\t\t}\n\n\t\t// Run any pre-migration hook before the SQL file. Hooks\n\t\t// receive the *pgxpool.Pool (not the loop's pinned conn), so\n\t\t// they can acquire other session-level locks without\n\t\t// colliding with migrationAdvisoryLockKey. Hook failures\n\t\t// abort the run before schema_migrations is updated, so the\n\t\t// same version retries cleanly on the next invocation.\n\t\tif hook, ok := opts.Hooks[version]; ok && hook != nil {\n\t\t\tslog.Info(\"running pre-migration hook\", \"version\", version, \"direction\", opts.Direction)\n\t\t\tif err := hook(ctx, pool); err != nil {\n\t\t\t\treturn fmt.Errorf(\"pre-migration hook for %q (%s): %w\", version, opts.Direction, err)\n\t\t\t}\n\t\t}\n\n\t\tif _, err := conn.Exec(ctx, string(sql)); err != nil {\n\t\t\treturn fmt.Errorf(\"apply migration %q: %w\", file, err)\n\t\t}","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/migrate/main.go#L406-L442","documentation":"os.ReadFile failed for a migration SQL file listed in opts.Files. The runner needs the file's bytes to exec it; failure means the path does not exist, is a directory, or the process lacks read permission. The path is exactly what was passed in the file list, so this usually indicates the files were moved/deleted between listing and reading, or the list was built against a different root.","triggerScenarios":"Embedded-vs-disk mismatch: opts.Files contains absolute/relative paths from a build step but the binary runs where those paths do not exist; file deleted between discovery and read; permission changes (e.g. container user differs from file owner).","commonSituations":"Running the migrate binary from a different working directory with relative file globs; CI cache stale; container image built without copying the migrations directory.","solutions":["Verify the exact path from the error exists at runtime: ls -l <path>","Use absolute paths or embed the migrations via go:embed so the binary is self-contained","If containerized, confirm the migrations dir is COPYed into the image and readable by the runtime user"],"exampleFix":"# before\nmigrate -files=./migrations/*.sql   # relative to cwd, wrong cwd at runtime\n\n# after\nmigrate -files=/app/migrations/*.sql\n# or embed in Go:\n//go:embed migrations/*.sql\nvar migrationFS embed.FS","handlingStrategy":"validation","validationCode":"for _, f := range files {\n    if _, err := os.Stat(f); err != nil {\n        log.Fatalf(\"migration file missing: %s\", f)\n    }\n}","typeGuard":null,"tryCatchPattern":"sql, err := os.ReadFile(file)\nif err != nil {\n    return fmt.Errorf(\"read migration %q: %w\", file, err)\n}","preventionTips":["Use absolute paths or go:embed for migration files so cwd cannot break runs","Verify the migrations directory exists in container images (COPY + readable)","Fail fast on stat-checks over the file list before starting the DB work"],"tags":["go","filesystem","migration","packaging"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}