yikart/AiToEarn · error · AppException

ResponseCode.ConfigEditorValidationFailed

ResponseCode.ConfigEditorValidationFailed

Error message

ConfigEditorValidationFailed

What it means

validateConfigValue requires the ConfigEditorConfig.schema to be a usable Zod schema — either a Zod DTO (from createZodDto, unwrapped via isZodDto) or a raw z.ZodType instance. If after that unwrapping the value is not a z.ZodType, the library cannot validate anything and throws ConfigEditorValidationFailed with no message.

Source

Thrown at project/aitoearn-backend/libs/config-editor/src/config-editor.service.ts:66

  private parseConfig(content: string, format: ConfigFileFormat) {
    try {
      return format === ConfigFileFormat.Json
        ? JSON.parse(content)
        : parseYaml(content)
    }
    catch (error) {
      throw new AppException(
        ResponseCode.ConfigEditorParseFailed,
        error instanceof Error ? error.message : String(error),
      )
    }
  }

  private validateConfigValue(config: unknown): Record<string, unknown> {
    const schema = isZodDto(this.config.schema) ? this.config.schema.schema : this.config.schema
    if (!(schema instanceof z.ZodType)) {
      throw new AppException(ResponseCode.ConfigEditorValidationFailed)
    }

    const result = schema.safeParse(config)
    if (!result.success) {
      throw new AppException(ResponseCode.ConfigEditorValidationFailed, z.prettifyError(result.error))
    }
    return result.data as Record<string, unknown>
  }

  private serializeConfig(config: Record<string, unknown>, format: ConfigFileFormat) {
    if (format === ConfigFileFormat.Json) {
      return `${JSON.stringify(config, null, 2)}\n`
    }
    return stringifyYaml(config)
  }

  private async readConfigFile(configPath: string) {
    try {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Pass a zod schema (z.object({...})) or a createZodDto(...) result as the schema option
  2. Check `pnpm why zod` / lockfile for duplicate zod versions; dedupe so the same zod instance is shared with @yikart/common
  3. If using a ZodDto class, make sure it was created with createZodDto so isZodDto recognizes it
  4. Log/inspect the schema value at registration to confirm it is defined and non-null

Example fix

// before
ConfigEditorModule.register({ configPath: 'config/app.yaml', schema: AppConfig }) // plain interface
// after
const AppConfigSchema = z.object({ port: z.number() })
ConfigEditorModule.register({ configPath: 'config/app.yaml', schema: AppConfigSchema })
Defensive patterns

Strategy: validation

Validate before calling

import { z } from 'zod'
if (!(schema instanceof z.ZodType) && !isZodDto(schema))
  throw new Error('ConfigEditor schema must be a zod schema or createZodDto result')

Type guard

function isUsableSchema(s: unknown): s is z.ZodType {
  const inner = isZodDto(s) ? s.schema : s
  return inner instanceof z.ZodType
}

Try / catch

try {
  editor.validateConfig(payload)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.ConfigEditorValidationFailed && !e.message)
    logger.error('Schema itself is not a ZodType — fix module registration')
  throw e
}

Prevention

When it happens

Trigger: ConfigEditorModule is registered with a schema that is neither a Zod DTO nor a z.ZodType: e.g. a plain object, a class without createZodDto, a JSON-Schema/class-validator schema, undefined/null schema, or a zod version mismatch making `instanceof z.ZodType` fail across duplicate zod copies.

Common situations: Passing a plain TS interface (types vanish at runtime); passing a class decorated for class-validator instead of a Zod DTO; importing z from two different zod package instances (v3 vs v4 or duplicate installs) so instanceof fails; forgetting the schema option entirely.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/b10fccb2fb5ebe60. Report an issue: GitHub.