RocketChat/Rocket.Chat · error

Attempted to store an invalid data type, it must be an…

Error message

Attempted to store an invalid data type, it must be an object.

What it means

AppPersistenceBridge.create stores documents as { appId, data } in the app persistence collection and enforces typeof data === 'object' before inserting. Primitives (string, number, boolean, undefined, function) are rejected with this Error. Note the guard's blind spots: typeof null === 'object' lets null through, and arrays also pass.

Solutions

  1. Store a plain object — wrap scalars as { value: someScalar } if you only need one
  2. If you have a JSON string, JSON.parse it before create
  3. Double-check property names/typos that produce undefined
  4. For associated storage, the same rule applies to createWithAssociations

Example fix

// before
await app.getPersistence().create(JSON.stringify({ status: 'done' })); // string -> throws
// after
await app.getPersistence().create({ status: 'done' });
Defensive patterns

Strategy: type-guard

Validate before calling

const data = JSON.parse(rawJson) as Record<string, unknown>;
await app.getPersistence().create(data);

Type guard

const isPersistableObject = (d: unknown): d is Record<string, unknown> =>
  typeof d === 'object' && d !== null && !Array.isArray(d);

if (!isPersistableObject(payload)) throw new Error('persistence payload must be a non-null object');
await app.getPersistence().create(payload);

Try / catch

try {
  await app.getPersistence().create(payload);
} catch (err) {
  if (err instanceof Error && err.message.includes('invalid data type')) {
    throw new Error(`persistence.create received ${typeof payload} — wrap primitives in an object`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling persistence.create(JSON.stringify(payload)) (a string); passing a number/boolean flag; passing undefined because the variable or property was misspelled or never set.

Common situations: Developers serializing before storing out of habit; migrating code that stored scalars; optional values that silently resolve to undefined; test data built inline as strings.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/0c37e548ca89e698. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/app/apps/server/bridges/persistence.ts:21

import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata';
import type { InsertOneResult } from 'mongodb';

export class AppPersistenceBridge extends PersistenceBridge {
	constructor(private readonly orch: IAppServerOrchestrator) {
		super();
	}

	protected async purge(appId: string): Promise<void> {
		this.orch.debugLog(`The App's persistent storage is being purged: ${appId}`);

		await this.orch.getPersistenceModel().remove({ appId });
	}

	protected async create(data: object, appId: string): Promise<string> {
		this.orch.debugLog(`The App ${appId} is storing a new object in their persistence.`);

		if (typeof data !== 'object') {
			throw new Error('Attempted to store an invalid data type, it must be an object.');
		}

		return this.orch
			.getPersistenceModel()
			.insertOne({ appId, data })
			.then(({ insertedId }: InsertOneResult) => (insertedId as unknown as string) || '');
	}

	protected async createWithAssociations(data: object, associations: Array<RocketChatAssociationRecord>, appId: string): Promise<string> {
		this.orch.debugLog({
			msg: `The App ${appId} is storing a new object in their persistence that is associated with some models.`,
			associations,
		});

		if (typeof data !== 'object') {
			throw new Error('Attempted to store an invalid data type, it must be an object.');
		}

View on GitHub (pinned to b2c16d5842)