linshenkx/prompt-optimizer · error · FavoriteValidationError

Favorite entry must be an object

Error message

Favorite entry must be an object

What it means

normalizeFavoriteRecord requires its input to be a plain object (isPlainObject). Null, arrays, strings, numbers, or anything non-object throw FavoriteValidationError before any field normalization runs.

Source

Thrown at packages/core/src/services/favorite/storage-guards.ts:163

  if (softLimitExceeded && options?.warnOnSoftLimit) {
    const logWarning = options.logWarning ?? console.warn
    logWarning(
      `favorites payload exceeds soft limit (${totalBytes} bytes > ${FAVORITES_SOFT_LIMIT_BYTES} bytes)`,
    )
  }

  return {
    totalBytes,
    softLimitExceeded,
  }
}

export const normalizeFavoriteRecord = (
  value: unknown,
  fallbackTimestamp = Date.now(),
): FavoritePrompt => {
  if (!isPlainObject(value)) {
    throw new FavoriteValidationError('Favorite entry must be an object')
  }

  const raw = value as Record<string, unknown>
  const rawContent = typeof raw.content === 'string' ? raw.content : ''
  if (!rawContent.trim()) {
    throw new FavoriteValidationError('Favorite prompt content cannot be empty')
  }

  const content = rawContent
  const metadata = isPlainObject(raw.metadata) ? { ...raw.metadata } : undefined
  const originalContent = toTrimmedString(raw.originalContent)
  const nextMetadata = originalContent
    ? { ...(metadata || {}), originalContent }
    : metadata

  assertFavoriteMetadataHasNoInlineImages(nextMetadata)

  let functionMode: FavoritePrompt['functionMode'] = isFunctionMode(raw.functionMode)

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Inspect the persisted favorites array and remove or repair non-object entries
  2. Run a one-time cleanup that filters entries with a plain-object check before loading
  3. If data is unrecoverable, export what is valid, reset the store, and re-import

Example fix

// before
const favorites = raw.map(normalizeFavoriteRecord); // raw contains 'oops'

// after
const isPlainObject = (v: unknown) => typeof v === 'object' && v !== null && !Array.isArray(v);
const favorites = raw.filter(isPlainObject).map(normalizeFavoriteRecord);
Defensive patterns

Strategy: type-guard

Validate before calling

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
  typeof v === 'object' && v !== null && !Array.isArray(v);
const clean = raw.filter(isPlainObject); // drop nulls/primitives/arrays before normalize

Type guard

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

Try / catch

try {
  const fav = normalizeFavoriteRecord(value);
} catch (e) {
  if (e instanceof FavoriteValidationError && /must be an object/.test(e.message)) {
    // skip or repair the malformed record
  }
}

Prevention

When it happens

Trigger: Passing or reading from storage a favorites array entry that is null, a primitive, or an array instead of an object — normalization is used when loading persisted records.

Common situations: Persisted favorites edited manually in devtools, sync conflicts writing malformed entries, or schema migrations leaving non-object entries in the store.

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 linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/cdb944fb8ee354b4. Report an issue: GitHub.