{"record":{"id":"5029127c02e124aa","repo":"weaviate/weaviate","slug":"close-s-w","errorCode":null,"errorMessage":"close %s: %w","messagePattern":"close (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"adapters/repos/db/inverted_reindex_finalize.go","lineNumber":393,"sourceCode":"// dataset; FinalizeCompletedMigrations needs the swapped/tidied\n// sentinels in order to drive its existing ingest→canonical rename\n// path. Writing them retroactively is safe because no buckets are\n// loaded yet (we are pre-shard-init) and the underlying invariant\n// (ingest dir holds the right data) has been verified by the\n// `markMerged` semantics. We do NOT write swapped-per-prop sentinels\n// because the existing finalize loop does not consume them.\nfunc writeRecoveryTidiedSentinels(migDir string) error {\n\tfor _, name := range []string{\"swapped.mig\", \"tidied.mig\"} {\n\t\tp := filepath.Join(migDir, name)\n\t\tif fileExists(p) {\n\t\t\tcontinue\n\t\t}\n\t\tf, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"create %s: %w\", name, err)\n\t\t}\n\t\tif err := f.Close(); err != nil {\n\t\t\treturn fmt.Errorf(\"close %s: %w\", name, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// removeStaleSidecarsForGen removes the `__<...>_<gen>` sidecar dirs\n// (reindex/ingest/backup) belonging to an older, superseded generation\n// of a finalized migration. Looks up the per-strategy suffix bases via\n// `migrationSuffixes` (which now returns the suffix bases without the\n// `_<N>` part) and removes any matching dir for the specific `_<gen>`.\n//\n// Props are read from the older gen's `properties.mig` (or recovered\n// from the on-disk dirs themselves if properties.mig is missing — the\n// latter is defensive against partial pre-migration state).\nfunc removeStaleSidecarsForGen(lsmPath, namespace, dirName string, logger logrus.FieldLogger) {\n\tmigDir := filepath.Join(lsmPath, \".migrations\", dirName)\n\tsuffixes := migrationSuffixes(dirName)\n\tif suffixes == nil {","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/weaviate/weaviate/blob/75aa4b6d11f8818305aafd4440b4e32794f7ca04/adapters/repos/db/inverted_reindex_finalize.go#L375-L411","documentation":"After successfully creating a recovery sentinel file, writeRecoveryTidiedSentinels closes it. If f.Close() fails (deferred flush/FS error, e.g. ENOSPC or EIO surfaced on close), the error is wrapped with the sentinel name and aborts FinalizeCompletedMigrations.","triggerScenarios":"Close-time flush fails due to disk full or I/O error; the file descriptor became invalid; underlying storage fault on the data volume.","commonSituations":"Disk full at exactly the sentinel-write moment; failing disk or network storage (EIO); container storage driver issues.","solutions":["Free disk space and retry node startup/migration","Check disk/volume health (dmesg, smart data) for I/O errors","The sentinel file may exist but be suspect — verify it and recreate if empty/corrupt","Move data to reliable local storage rather than flaky network mounts"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-check storage health\nif err := checkDiskWritable(dataDir); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := finalize(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"close \") {\n\t\t// EIO/ENOSPC on close: fix storage, verify/recreate sentinel, restart node\n\t}\n}","preventionTips":["Keep healthy headroom on data disks (close flushes can surface ENOSPC)","Avoid unreliable network filesystems for the data directory","Check dmesg/smart for failing disks if close errors recur"],"tags":["filesystem","io","migration"],"backgroundTag":"file-close-failed","analyzedSha":"75aa4b6d11f8818305aafd4440b4e32794f7ca04","analyzedAt":"2026-09-04T14:58:20.392Z","contentChangedAt":"2026-09-04T14:58:20.392Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}