langgenius/dify · error · ValidationError

rating must be either 'like' or 'dislike'

Error message

rating must be either 'like' or 'dislike'

What it means

Thrown by ensureRating() in validation.ts:80 as a ValidationError. The message feedback API accepts only 'like' or 'dislike' (or null/undefined to clear). Any other string or type is rejected. Called from messageFeedback() in base.ts for both the positional and object-form overloads.

Source

Thrown at sdks/nodejs-client/src/client/validation.ts:80

    if (typeof item !== 'string' || item.trim().length === 0) {
      throw new ValidationError(`${name} must contain non-empty strings`)
    }
  })
}

export function ensureOptionalStringArray(value: unknown, name: string): void {
  if (value === undefined || value === null) {
    return
  }
  ensureStringArray(value, name)
}

export function ensureRating(value: unknown): void {
  if (value === undefined || value === null) {
    return
  }
  if (value !== 'like' && value !== 'dislike') {
    throw new ValidationError("rating must be either 'like' or 'dislike'")
  }
}

export function validateParams(params: Record<string, unknown>): void {
  Object.entries(params).forEach(([key, value]) => {
    if (value === undefined || value === null) {
      return
    }

    // Only check max length for strings; empty strings are allowed for optional params
    // Required fields are validated at method level via ensureNonEmptyString
    if (typeof value === 'string') {
      if (value.length > MAX_STRING_LENGTH) {
        throw new ValidationError(
          `Parameter '${key}' exceeds maximum length of ${MAX_STRING_LENGTH} characters`,
        )
      }
    } else if (Array.isArray(value)) {

View on GitHub (pinned to ef8544b173)

Solutions

  1. Map your UI value to the SDK vocabulary: const rating = vote === 'up' ? 'like' : 'dislike'.
  2. Pass null/undefined (not 'none') when clearing feedback.
  3. Constrain the rating type to 'like' | 'dislike' | null at the call site.

Example fix

// before
await client.messageFeedback(msgId, 'Like', user)

// after
await client.messageFeedback(msgId, 'like', user)
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeRating(value: unknown): 'like' | 'dislike' | undefined {
  if (value === undefined || value === null) return undefined
  if (value === 'like' || value === 'dislike') return value
  if (value === 'up' || value === 1 || value === true) return 'like'
  if (value === 'down' || value === -1 || value === false) return 'dislike'
  throw new Error(`rating must be 'like' or 'dislike'`)
}

Type guard

function isRating(value: unknown): value is 'like' | 'dislike' {
  return value === 'like' || value === 'dislike'
}

Try / catch

try {
  await client.messageFeedback(msgId, rating, user)
} catch (err) {
  if (err instanceof Error && /rating must be either/.test(err.message)) {
    // map UI vote to canonical string and retry
    await client.messageFeedback(msgId, rating === 'up' ? 'like' : 'dislike', user)
  } else throw err
}

Prevention

When it happens

Trigger: Calling client.messageFeedback(msgId, 'Like', user) (wrong case), client.messageFeedback(msgId, 'up', user), or client.messageFeedback({ messageId, user, rating: 1 }). null and undefined pass through as 'clear feedback'.

Common situations: UI controls that emit 'up'/'down' or +1/-1; case differences from user input; numeric ratings from a 5-star widget routed into a binary field.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/3881caf6d467d29d. Report an issue: GitHub.