Error: RealmConfig::path is required after upgrading React Native + Realm
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.
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.
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 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.
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.
Happy you got the issue resolved š