{"record":{"id":"374f674d67b3b4d3","repo":"gofr-dev/gofr","slug":"failed-to-create-migration-file-received-nil-file","errorCode":null,"errorMessage":"failed to create migration file: received nil file handle","messagePattern":"failed to create migration file: received nil file handle","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/migration/opentsdb.go","lineNumber":36,"sourceCode":"\tfilePath string\n}\n\ntype openTSDBMigrator struct {\n\tfilePath string\n\tmigrator\n\tmu sync.Mutex\n}\n\ntype tsdbMigrationRecord struct {\n\tVersion   int64  `json:\"version\"`\n\tMethod    string `json:\"method\"`\n\tStartTime string `json:\"start_time\"`\n\tDuration  int64  `json:\"duration\"`\n}\n\nconst dirPerm = 0755\n\nvar errNilFileHandle = errors.New(\"failed to create migration file: received nil file handle\")\n\n// apply initializes openTSDBMigrator using the openTsdbDS.\nfunc (ds openTSDBDS) apply(m migrator) migrator {\n\treturn &openTSDBMigrator{ // Return pointer to avoid copying the mutex\n\t\tfilePath: ds.filePath,\n\t\tmigrator: m,\n\t}\n}\n\n// checkAndCreateMigrationTable ensures the migration directory and file structure exists.\n// It only creates an empty file if no migration file exists at all.\nfunc (om *openTSDBMigrator) checkAndCreateMigrationTable(c *container.Container) error {\n\tom.mu.Lock()\n\tdefer om.mu.Unlock()\n\n\t// Ensure directory exists\n\tdir := filepath.Dir(om.filePath)\n\tif dir != \".\" {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/migration/opentsdb.go#L18-L54","documentation":"errNilFileHandle is returned by createEmptyMigrationFile when the file-creation path yields a nil *os.File handle, i.e., the migrator could not obtain a valid handle for the OpenTSDB migration file. This is a defensive guard against proceeding with a nil file that would panic on write/close.","triggerScenarios":"createEmptyMigrationFile gets a nil file handle after attempting to create the migration file — typically an OS-level create failure path that slipped past the error check, or a nil result from the file-creation helper.","commonSituations":"Read-only filesystem or missing/uncreatable parent directory for the migration file path; permission denied; misconfigured filePath pointing into a nonexistent mount.","solutions":["Check that the directory of the configured migration file path exists and is writable","Fix the filePath configuration for the OpenTSDB datasource","Ensure the process user has write permissions at that path","Pre-create the parent directory (the migrator uses dirPerm 0755 via MkdirAll)"],"exampleFix":"// before\nfilePath: \"/mnt/ro-fs/gofr_migrations.json\" // read-only mount -> nil handle\n// after\nfilePath: \"/var/lib/app/gofr_migrations.json\" // writable location","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(cfg.OpenTSDBMigrationFile)\nif err := os.MkdirAll(dir, 0755); err != nil {\n    return fmt.Errorf(\"cannot prepare migration dir: %w\", err)\n}\nf, err := os.OpenFile(cfg.OpenTSDBMigrationFile, os.O_CREATE|os.O_WRONLY, 0644)\nif err != nil || f == nil {\n    return errors.New(\"migration file path not writable\")\n}\nf.Close()","typeGuard":"func validFileHandle(f *os.File) bool { return f != nil }","tryCatchPattern":null,"preventionTips":["Configure filePath under a directory known to be writable by the app user","Pre-create the migration directory in your deploy/Dockerfile","Avoid read-only root filesystems for migration file storage (use a volume)","Test migrations in the container image with the same user it runs as"],"tags":["opentsdb","migration","filesystem"],"backgroundTag":"nil-file-handle","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}