ATH-MaaS/Pixelle-Video · error · ValueError

Invalid response format: missing 'narrations' key

Error message

Invalid response format: missing 'narrations' key

What it means

generate_narrations_from_topic parses the LLM response as JSON and requires a top-level "narrations" key; ValueError is raised when the model's output doesn't match the expected schema. This guards against LLMs returning prose, wrapped markdown, or differently named keys.

Source

Thrown at pixelle_video/utils/content_generators.py:138

        topic=topic,
        n_storyboard=n_scenes,
        min_words=min_words,
        max_words=max_words
    )
    
    response = await llm_service(
        prompt=prompt,
        temperature=0.8,
        max_tokens=2000
    )
    
    logger.debug(f"LLM response: {response[:200]}...")
    
    # Parse JSON
    result = _parse_json(response)
    
    if "narrations" not in result:
        raise ValueError("Invalid response format: missing 'narrations' key")
    
    narrations = result["narrations"]
    
    # Validate count
    if len(narrations) > n_scenes:
        logger.warning(f"Got {len(narrations)} narrations, taking first {n_scenes}")
        narrations = narrations[:n_scenes]
    elif len(narrations) < n_scenes:
        raise ValueError(f"Expected {n_scenes} narrations, got only {len(narrations)}")
    
    logger.info(f"Generated {len(narrations)} narrations successfully")
    return narrations


async def generate_narrations_from_content(
    llm_service,
    content: str,
    n_scenes: int = 5,

View on GitHub (pinned to 848b054e4f)

Solutions

  1. Check the logged 'LLM response' debug line to see the actual shape returned
  2. Strengthen the prompt to demand exactly {"narrations": [...]} with n_scenes items
  3. Lower temperature / use a model that reliably follows JSON instructions
  4. Add few-shot examples of the expected JSON in the prompt

Example fix

// model returned {"scenes": ["a","b"]}
// before
narrations = result["scenes"]
// after (fix the prompt, or normalize)
if "narrations" not in result and "scenes" in result:
    result = {"narrations": result["scenes"]}
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_narration_result(result, n_scenes: int) -> bool:
    return (
        isinstance(result, dict)
        and isinstance(result.get('narrations'), list)
        and len(result['narrations']) == n_scenes
        and all(isinstance(n, str) and n.strip() for n in result['narrations'])
    )

Type guard

def has_narrations(x) -> bool:
    return isinstance(x, dict) and isinstance(x.get('narrations'), list)

Try / catch

try:
    narrations = await generate_narrations_from_topic(topic, n_scenes=n)
except ValueError as e:
    if 'missing' in str(e):
        narrations = await generate_narrations_from_topic(topic, n_scenes=n, retry_with_stricter_schema=True)
    else:
        raise

Prevention

When it happens

Trigger: Calling generate_narration/generate_content which routes here when the LLM reply, after _parse_json, is a dict without "narrations" — e.g. the model returned {"scenes": [...]}, a bare array, or explanation text instead of the requested JSON schema.

Common situations: Weak/non-instruct models ignoring the JSON schema; temperature too high producing prose; prompt template edited so the schema instruction is lost; model wrapping JSON in markdown fences that _parse_json strips only partially.

Related errors


AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30). Data as JSON: /api/errors/cdf4fa1b1213a899. Report an issue: GitHub.