Causes of Validation Failures for Missing React Props Interface in Stitch Skills

Validation fails when a React component in the stitch-skills framework lacks a TypeScript interface ending with Props, which the validator searches for using the TypeScript compiler API.

The React Component Skill in the google-labs-code/stitch-skills repository enforces strict TypeScript validation to ensure JSON props match component definitions. When validation fails with a "Missing Props interface" error, it typically stems from specific naming convention violations or missing interface declarations in the component file. Understanding how the validateComponent function parses TypeScript source files reveals exactly why these validation failures occur.

How the Validator Detects Missing Props Interfaces

The validation logic resides in plugins/stitch-build/skills/react-components/scripts/validate.js. When the skill receives a request to render a component, it invokes validateComponent(componentDir, componentName, props) to ensure the component adheres to the required contract.

The TypeScript Compiler API Walk

The validator uses the TypeScript compiler API to parse the component file into an AST. In the getPropsInterface function (lines 6-26), it reads the source file and creates a TypeScript source file object:

const source = fs.readFileSync(componentPath, 'utf8');
const sourceFile = ts.createSourceFile(
  componentPath,
  source,
  ts.ScriptTarget.Latest,
  true
);

It then traverses the AST using ts.forEachChild, looking for InterfaceDeclaration nodes:

ts.forEachChild(sourceFile, (node) => {
  if (ts.isInterfaceDeclaration(node)) {
    if (node.name.text.endsWith('Props')) {
      interfaceName = node.name.text;
    }
  }
});

The Props Suffix Requirement

The validation logic specifically checks for interface names ending with the string Props (line 19). If no interface matching this pattern is found, getPropsInterface returns null, triggering the error in validateComponent (lines 35-38):

const propsInterface = getPropsInterface(componentPath);
if (!propsInterface) {
  throw new Error(`Missing Props interface for component ${componentName}`);
}

Common Causes of Validation Failures

Undeclared Props Interfaces

The most straightforward cause occurs when a component file contains no TypeScript interface at all. The validator expects every component to explicitly define its contract through an interface that describes the expected JSON props structure.

Failing example (src/components/Card.tsx):

import React from "react";

const Card: React.FC<any> = (props) => (
  <div className="card">
    <h2>{props.title}</h2>
    <p>{props.content}</p>
  </div>
);

export default Card;

This component lacks any interface declaration, causing getPropsInterface to return null and the validator to throw: "Missing Props interface for component Card".

Non-Standard Interface Naming

The validator requires the interface name to end with Props. Using alternative naming conventions prevents the AST walker from recognizing the interface.

Failing example:

export interface CardProperties {
  title: string;
  content: string;
}

Because CardProperties does not end with Props, the validation fails even though the interface is correctly exported.

Component File Resolution Errors

Before checking for the Props interface, the validator verifies the component file exists (lines 31-33):

const componentPath = path.join(componentDir, `${componentName}.tsx`);
if (!fs.existsSync(componentPath)) {
  throw new Error(`Component file not found: ${componentPath}`);
}

If the file is missing or misnamed (for example, card.tsx instead of Card.tsx), validation fails with a file-not-found error before the Props interface check occurs.

Example Scenarios and Solutions

Correct implementation (following the template in component-template.tsx):

import React from "react";

export interface CardProps {
  title: string;
  content: string;
}

const Card: React.FC<CardProps> = ({ title, content }) => (
  <div className="card">
    <h2>{title}</h2>
    <p>{content}</p>
  </div>
);

export default Card;

This satisfies the validation rules defined in SKILL.md (lines 33-35) and allows the skill to proceed with type checking. The interface is exported, follows the {ComponentName}Props naming convention, and resides in the expected file location.

Summary

  • The React Component Skill requires every component to export a TypeScript interface ending with Props to validate incoming JSON data.
  • The validator uses the TypeScript compiler API to parse src/components/{ComponentName}.tsx and searches for interface declarations matching the Props suffix pattern.
  • Validation fails when the interface is missing, uses an incorrect name (like Properties instead of Props), or when the component file cannot be found at the expected path.
  • The error message "Missing Props interface for component {Name}" originates from validate.js lines 36-38 when the AST walker finds no matching interface.

Frequently Asked Questions

Why must the interface name end with "Props"?

The getPropsInterface function in validate.js explicitly checks for interface names ending with Props using node.name.text.endsWith('Props'). This convention ensures the validator can reliably distinguish between component props and other interfaces (like state interfaces or utility types) that might exist in the file.

Can I use a type alias instead of an interface?

According to the source code in validate.js, the validator only searches for InterfaceDeclaration nodes using ts.isInterfaceDeclaration(node). Type aliases declared with type are not checked, so using type CardProps = { ... } will cause validation to fail with a missing interface error.

What file path should my component use?

The skill expects components at src/components/{ComponentName}.tsx with exact case matching, as implemented in validateComponent (line 30). For a component named Card, the file must be src/components/Card.tsx, not card.tsx or Card/index.tsx.

How do I debug validation failures locally?

Run the validation script directly using Node.js before deployment. The validate.js file exports validateComponent, which you can call with your local components directory path to verify your Props interface is detected correctly before the skill processes the request.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →