linshenkx/prompt-optimizer · error · Error

Missing optimizerTarget.subModeKey

Error message

Missing optimizerTarget.subModeKey

What it means

After schema checks pass, the importer requires routing metadata: data.optimizerTarget.subModeKey must exist, be a string, and be non-empty after trimming. This key tells the importer which optimizer sub-mode the prompt targets; without it the imported prompt cannot be routed.

Source

Thrown at packages/ui/src/composables/app/useAppPromptGardenImport.ts:542

  const parseV1 = (data: unknown): FetchedPrompt => {
    if (!isPlainObject(data)) {
      throw new Error('Garden response must be a JSON object')
    }
    if (data.schema !== 'prompt-garden.prompt.v1') {
      throw new Error('Unsupported Garden response schema')
    }
    if (data.schemaVersion !== 1) {
      throw new Error('Unsupported Garden response schemaVersion')
    }

    const optimizerTarget = isPlainObject(data.optimizerTarget) ? data.optimizerTarget : null
    const optimizerTargetKey =
      optimizerTarget && typeof optimizerTarget.subModeKey === 'string'
        ? optimizerTarget.subModeKey.trim()
        : ''
    if (!optimizerTargetKey) {
      throw new Error('Missing optimizerTarget.subModeKey')
    }

    const prompt = isPlainObject(data.prompt) ? data.prompt : null
    const format = prompt && (prompt.format === 'text' || prompt.format === 'messages')
      ? (prompt.format as 'text' | 'messages')
      : null
    if (!format) {
      throw new Error('Missing prompt.format')
    }

    let promptText: string | undefined
    let promptMessages: ConversationMessage[] | undefined
    if (format === 'text') {
      const t = prompt && typeof prompt.text === 'string' ? prompt.text : ''
      if (!t.trim()) {
        throw new Error('Empty prompt.text')
      }
      promptText = t

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Add an optimizerTarget object with a non-empty string subModeKey to the payload (e.g. {"optimizerTarget":{"subModeKey":"default"}})
  2. Verify the export flow on the Garden side actually captures the sub-mode key
  3. If the key is genuinely optional for your use case, patch parseV1 to fall back to a default instead of throwing

Example fix

// before
{ "prompt": { ... }, "optimizerTarget": {} }

// after
{ "prompt": { ... }, "optimizerTarget": { "subModeKey": "quality" } }
Defensive patterns

Strategy: type-guard

Validate before calling

const key = raw?.optimizerTarget?.subModeKey
if (typeof key !== 'string' || !key.trim()) { /* block import with clear message */ }

Type guard

const hasOptimizerTarget = (d: unknown): d is { optimizerTarget: { subModeKey: string } } =>
  isPlainObject(d) && isPlainObject(d.optimizerTarget) && typeof d.optimizerTarget.subModeKey === 'string' && d.optimizerTarget.subModeKey.trim() !== ''

Try / catch

catch (e) { if (e.message === 'Missing optimizerTarget.subModeKey') promptUserToPickSubMode(); else throw e }

Prevention

When it happens

Trigger: optimizerTarget is missing, not a plain object, subModeKey is absent/null/number, or is a whitespace-only string after trim().

Common situations: Prompts exported without an optimizer target selected; older exports that predate the optimizerTarget field; upstream data corruption; fixture prompts copied without the routing block.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/1a49facc3d47b5f3. Report an issue: GitHub.