realm-js icon indicating copy to clipboard operation
realm-js copied to clipboard

Error: RealmConfig::path is required after upgrading React Native + Realm

Open Ravisaksoft opened this issue 2 weeks ago • 2 comments

Hello team,

I’m facing an issue after upgrading React Native and Realm in Android. The same code base was working fine before the upgrade, but now I consistently get:

Error: RealmConfig::path is required

Environment Previously (working setup):

"react-native": "0.75.2",
"realm": "^12.13.1"

After upgrade (issue appears):

"react-native": "0.81.5",
"realm": "^20.2.0"
newArchEnabled=true
hermesEnabled=true

After the upgrade, calling Realm.open() with a custom encryption key and file name results in the error: Error: RealmConfig::path is required

Even though I am explicitly specifying a path: path: "default-new.realm"

Code Snippet

export const DBConfig = async (key) =>
  await new Promise((resolve, reject) => {
    const keyArray = key.split(',').map(Number);
    const encryptionKey = new Uint8Array(keyArray);

    Realm.open({
      schema: [
        DatabaseSchema.User
      ],
      path: "default-new.realm",
      encryptionKey: encryptionKey,
      schemaVersion: 8,
      migration: (oldRealm) => {
        if (oldRealm.schemaVersion < 8) {
          // migration logic (not needed in my case)
        }
      },
    })
      .then((realm) => {
        resolve(realm);
      })
      .catch((error) => {
        reject(error);
      });
  });

Note:

This issue occurs only on a cold start. The very first time the app launches, Realm throws the error RealmConfig::path is required. After that initial failure, all subsequent launches work normally and the database opens without any issues.

Ravisaksoft avatar Dec 06 '25 13:12 Ravisaksoft

Interesting indeed šŸ¤” This is not a synced realm, right? (judging by your configuration object).

Also, is it reproducible even without a particular Realm file? Or could you share this Realm file for further investigations?

Realistically, it's very unlikely that this will be solved as it's not a sync related issue and the SDKs have been deprecated, but perhaps someone from the community might be able to help you debug.

kraenhansen avatar Dec 06 '25 18:12 kraenhansen

Initialisation Code App.js (startup)

try {
  const key = await dbEncryption();
  await DBConfig(key);
} catch (e) {
  console.log("Error  ", e);
}

Here is the dbEncryption file

import { generateSecureRandom } from "react-native-securerandom";
import { getItem, saveItem } from "./SecureStorage";
import { isNil, isNull, isUndefined } from "lodash";
const REALM_DB_ENCRYPTION_NEW_KEY = "encryptedKey";
const REALM_DB_ENCRYPTION_OLD_KEY = "";
const REALM_DB_ENCRYPTION_UPDATE_KEY = "";

const dbEncryption = async () => {
	try {
		let updateEncryptedKey = await getItem(REALM_DB_ENCRYPTION_UPDATE_KEY);

		if (
			isNil(updateEncryptedKey) ||
			isNull(updateEncryptedKey) ||
			isUndefined(updateEncryptedKey)
		) {
			//New install
			const randomKey = await generateSecureRandom(64);
			await saveItem(REALM_DB_ENCRYPTION_UPDATE_KEY, randomKey.join(","));
			return await getItem(REALM_DB_ENCRYPTION_UPDATE_KEY);
		} else {
			//for existing user
			let updateEncryptedKey = await getItem(REALM_DB_ENCRYPTION_UPDATE_KEY);
			if (updateEncryptedKey) {
				return updateEncryptedKey;
			}
		}
	} catch (error) {
		return false;
	}
};

const resetEncryptionKey = async () => {
	dbEncryption.uniquekey = "ObfuscateMe";
	dbEncryption.uniquekey = "";
};

export default dbEncryption;
export { resetEncryptionKey };

------------ Here is my DBConfig.js-----------

import DatabaseSchema from "./DatabaseSchema";
import dbEncryption from "../../library/utils/DBEncryption";
import { generateSecureRandom } from "react-native-securerandom";
import {
	getItem,
	saveItem,
	removeItem
} from "../../library/utils/SecureStorage";
import { isNil, isNull, isUndefined, isEmpty } from "lodash";
// const Realm = require("realm");
import Realm from 'realm'
import RNFS from "react-native-fs";
const REALM_DB_ENCRYPTION_NEW_KEY = "";
const REALM_DB_ENCRYPTION_OLD_KEY = "";
const REALM_DB_ENCRYPTION_UPDATE_KEY = "REALM_DB_ENCRYPTION_UPDATE_KEY";

export const updateInfo = () => {
	return new Promise((resolve, reject) => {
		(async () => {
			try {
				const encryptedKey = await getItem(REALM_DB_ENCRYPTION_OLD_KEY);
				const newEncryptedKey = await getItem(REALM_DB_ENCRYPTION_NEW_KEY);
				const updateEncryptedKey = await getItem(
					REALM_DB_ENCRYPTION_UPDATE_KEY
				);

				const isOldKeyExist =
					!isNil(encryptedKey) &&
					!isNull(encryptedKey) &&
					!isUndefined(encryptedKey) &&
					!isEmpty(encryptedKey);
				const isNewKeyExist =
					!isNil(newEncryptedKey) &&
					!isNull(newEncryptedKey) &&
					!isUndefined(newEncryptedKey) &&
					!isEmpty(newEncryptedKey);
				const isUpdatedKeyExist =
					!isNil(updateEncryptedKey) &&
					!isNull(updateEncryptedKey) &&
					!isUndefined(updateEncryptedKey) &&
					!isEmpty(updateEncryptedKey);

				if (isUpdatedKeyExist) {
					await removeItem(REALM_DB_ENCRYPTION_OLD_KEY);
					await removeItem(REALM_DB_ENCRYPTION_NEW_KEY);
					resolve("Cleanup done.");
				} else if (isOldKeyExist || isNewKeyExist) {
					changeRealmEncryptionKey()
						.then(() => resolve("Migration done."))
						.catch((err) => reject(err));
				} else {
					const randomKey = await generateSecureRandom(64);
					await saveItem(REALM_DB_ENCRYPTION_UPDATE_KEY, randomKey.join(","));
					await getItem(REALM_DB_ENCRYPTION_UPDATE_KEY);
					resolve("No action needed.");
				}
			} catch (error) {
				reject(error);
			}
		})();
	});
};

const changeRealmEncryptionKey = () => {
	return new Promise((resolve, reject) => {
		(async () => {
			let oldRealm, newRealm, updateRealm;

			try {
				let oldEncryptedKey = await getItem(REALM_DB_ENCRYPTION_OLD_KEY);
				let newEncryptedKey = await getItem(REALM_DB_ENCRYPTION_NEW_KEY);
				let updateEncryptedKey = "";

				const isOldKeyExist =
					!isNil(oldEncryptedKey) &&
					!isNull(oldEncryptedKey) &&
					!isUndefined(oldEncryptedKey) &&
					!isEmpty(oldEncryptedKey);
				const isNewKeyExist =
					!isNil(newEncryptedKey) &&
					!isNull(newEncryptedKey) &&
					!isUndefined(newEncryptedKey) &&
					!isEmpty(newEncryptedKey);

				if (isOldKeyExist || isNewKeyExist) {
					const randomKey = await generateSecureRandom(64);
					await saveItem(REALM_DB_ENCRYPTION_UPDATE_KEY, randomKey.join(","));
					updateEncryptedKey = await getItem(REALM_DB_ENCRYPTION_UPDATE_KEY);
				}

				const schemas = [
					DatabaseSchema.User,
					DatabaseSchema.CurrentUserName,
					DatabaseSchema.Parameter,
					DatabaseSchema.AppLogsParameterSchema,
					DatabaseSchema.UUIDSchema,
					DatabaseSchema.TUEmailSchema,
					DatabaseSchema.AppVersionSchema,
					DatabaseSchema.PromotionalNotificationStatus,
					DatabaseSchema.GamificationEventQueue
				];

				if (isOldKeyExist) {
					oldRealm = await Realm.open({
						schema: schemas,
						encryptionKey: new Int8Array(oldEncryptedKey),
						path: "default.realm",
						schemaVersion: 8
					});
				} else {
					const encryptionKeynew = new Int8Array(newEncryptedKey);
					newRealm = await Realm.open({
						schema: schemas,
						encryptionKey: encryptionKeynew,
						path: "default.realm",
						schemaVersion: 8
					});
				}

				const keyArray = updateEncryptedKey.split(",").map(Number);
				const encryptionKey = new Uint8Array(keyArray);

				updateRealm = await Realm.open({
					path: "default-new.realm",
					schema: schemas,
					encryptionKey: encryptionKey,
					schemaVersion: 8
				});

				const sourceRealm = oldRealm || newRealm;

				updateRealm.write(() => {
					for (const schema of schemas) {
						const objects = sourceRealm.objects(schema.name);
						for (const obj of objects) {
							updateRealm.create(schema.name, { ...obj.toJSON() });
						}
					}
				});

				resolve(); // āœ… success
			} catch (error) {
				reject(error); // āŒ failure
			} finally {
				if (oldRealm) oldRealm.close();
				if (newRealm) newRealm.close();
				if (updateRealm) updateRealm.close();
				cleanup();
			}
		})();
	});
};
export const DBConfig = async (key) =>
  await new Promise(async(resolve, reject) => {
    console.log("DBConfig called with key:", key);

    // const keyArray = key.split(",").map(Number);
    // console.log("Converted key array:", keyArray);

    // const encryptionKey = new Uint8Array(keyArray);
    // console.log("Encryption key (Uint8Array):", encryptionKey);

    const UserSchema = {
      name: "User",
      primaryKey: "id",
      properties: {
        id: "int",
        name: "string",
        age: "int?",
        email: "string?",
        isActive: { type: "bool", default: true },
      },
    };
// const realmPath = `${RNFS.DocumentDirectoryPath}/default-new.realm`; 
//     console.log("Using absolute path:", realmPath);
   
const realmDir = RNFS.DocumentDirectoryPath;
    const realmPath = `${realmDir}/default-new.realm`;

    try {
        // Ensure the directory exists. This is often the missing piece on first install.
        const dirExists = await RNFS.exists(realmDir);
        if (!dirExists) {
            console.log("Directory does not exist, creating it:", realmDir);
            await RNFS.mkdir(realmDir);
        }
    } catch (e) {
        console.error("Failed to ensure Realm directory exists:", e);
        // Continue anyway, maybe RNFS handles it implicitly during open
    }
    // -------------------------------------------------

    console.log("Opening Realm with explicit absolute path:", realmPath);
 console.log("Opening Realm...");

    Realm.open({
      schema: [UserSchema],
      path: realmPath,
    //   encryptionKey: encryptionKey,
      schemaVersion: 8,
      migration: (oldRealm) => {
        console.log("Migration called. Old schema version:", oldRealm.schemaVersion);
        if (oldRealm.schemaVersion < 8) {
          // handle migration logic if needed
        }
      },
    })
      .then((realm) => {
        console.log("Realm opened successfully:", realm.path);
        resolve(realm);
      })
      .catch((error) => {
        console.error("Error opening Realm:", error);
        reject(error);
      });
  });

export const DBConfigClose = async () => {
	const key = await dbEncryption();
	const keyArray = key.split(",").map(Number);
	const encryptionKey = new Uint8Array(keyArray);
	const realRef = await Realm.open({
		schema: [
			DatabaseSchema.User,
			DatabaseSchema.CurrentUserName,
			DatabaseSchema.Parameter,
			DatabaseSchema.AppLogsParameterSchema,
			DatabaseSchema.UUIDSchema,
			DatabaseSchema.TUEmailSchema,
			DatabaseSchema.AppVersionSchema,
			DatabaseSchema.PromotionalNotificationStatus,
			DatabaseSchema.GamificationEventQueue
		],
		path: "default-new.realm",
		encryptionKey: encryptionKey, //updated key fetch function
		schemaVersion: 8,
		migration: (oldRealm) => {
			if (oldRealm.schemaVersion < 8) {
				// If this migration function is not supplied then any new properties are automatically added and old properties are removed
				// from the database when updating to the new schemaVersion.
				// If we need to update old or populate new properties when upgrading our version we can do this in this migration function.
			}
		}
	});
	realRef.close();
};
// export default  DBConfig;

const cleanup = () => {
	deleteOlderDatabase();
};

const deleteOlderDatabase = async () => {
	await removeItem(REALM_DB_ENCRYPTION_OLD_KEY);
	await removeItem(REALM_DB_ENCRYPTION_NEW_KEY);

	const realmPath = Realm.defaultPath;
	const auxFiles = ["", ".lock", ".note", ".management"];

	for (const ext of auxFiles) {
		const path = realmPath + ext;
		const exists = await RNFS.exists(path);
		if (exists) {
			await RNFS.unlink(path);
		}
	}
};

Ravisaksoft avatar Dec 07 '25 05:12 Ravisaksoft

@Ravisaksoft Can you post all your dependencies? Recently I get the similar problem, and I found that after I remove some OLD deprecated libraries like react-native-push-notificaiton

The problem is gone.

JohnnyChan2672 avatar Dec 11 '25 01:12 JohnnyChan2672

The issue is now resolved. The root cause was that Login.js was being executed before App.js, which caused the database to initialize on the login screen instead of during the app startup.

Ravisaksoft avatar Dec 12 '25 11:12 Ravisaksoft

Happy you got the issue resolved šŸ‘

kraenhansen avatar Dec 12 '25 11:12 kraenhansen