> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# Debugging

> Learn how to debug Preact applications with preact/debug and enable helpful error messages and warnings

# Debugging

Preact provides a powerful debugging addon that helps catch common mistakes and provides detailed error messages during development. The `preact/debug` package enhances your development experience with helpful warnings, prop type checking, and detailed component stack traces.

<Warning>
  The debug addon should only be imported in development environments. Never include it in production builds as it adds overhead and exposes detailed error information.
</Warning>

## Enabling Debug Mode

To enable debug mode, import `preact/debug` at the entry point of your application:

```javascript theme={null}
import 'preact/debug';
import { render } from 'preact';
import App from './App';

render(<App />, document.getElementById('app'));
```

<Tip>
  Import `preact/debug` as early as possible in your application to catch errors throughout your component tree.
</Tip>

With your bundler, you can conditionally import debug mode:

```javascript theme={null}
if (process.env.NODE_ENV !== 'production') {
  require('preact/debug');
}
```

## Error Detection

The debug addon catches many common mistakes and provides detailed error messages:

### Undefined Components

When you pass `undefined` to `createElement`, debug mode provides a helpful error:

```javascript theme={null}
// Forgot to export component
import { ComponentThatDoesntExist } from './components';

// Error: Undefined component passed to createElement()
// You likely forgot to export your component or might have 
// mixed up default and named imports
<ComponentThatDoesntExist />
```

Source: `debug/src/debug.js:153-159`

### Invalid Component Types

Debug mode detects when you accidentally pass JSX literals or invalid types:

```javascript theme={null}
// Accidentally passing a JSX literal twice
const MyComponent = <div>Hello</div>;
const vnode = <MyComponent />; // Error!

// Error: Invalid type passed to createElement()
// Did you accidentally pass a JSX literal as JSX twice?
```

Source: `debug/src/debug.js:160-176`

### Invalid Refs

Refs must be functions or objects created by `createRef()`:

```javascript theme={null}
// Invalid: string ref
<div ref="myRef" /> // Error!

// Valid: function ref
<div ref={el => this.myRef = el} />

// Valid: ref object
const myRef = createRef();
<div ref={myRef} />
```

Source: `debug/src/debug.js:178-190`

### Event Handler Validation

Event handlers must be functions:

```javascript theme={null}
// Invalid: non-function event handler
<button onClick="handleClick"> // Error!

// Valid
<button onClick={handleClick}>
```

Source: `debug/src/debug.js:192-208`

## Render Loop Detection

Debug mode prevents infinite render loops by tracking consecutive renders:

```javascript theme={null}
function BadComponent() {
  const [state, setState] = useState(0);
  
  // This creates an infinite loop!
  setState(state + 1);
  
  return <div>{state}</div>;
}

// Error: Too many re-renders. This is limited to prevent an 
// infinite loop which may lock up your browser.
```

The limit is set to 25 consecutive renders. Source: `debug/src/debug.js:262-269`

## HTML Nesting Validation

Debug mode validates proper HTML nesting according to web standards:

### Table Element Nesting

```javascript theme={null}
// Error: Improper nesting
<table>
  <tr> // Missing <tbody>
    <td>Cell</td>
  </tr>
</table>

// Valid
<table>
  <tbody>
    <tr>
      <td>Cell</td>
    </tr>
  </tbody>
</table>
```

Source: `debug/src/debug.js:358-440`

### Paragraph Element Validation

```javascript theme={null}
// Error: Invalid children in <p>
<p>
  <div>Block element not allowed</div>
</p>

// Valid
<p>
  <span>Inline element is fine</span>
</p>
```

Source: `debug/src/debug.js:416-428`

### Interactive Content Nesting

```javascript theme={null}
// Error: Nested interactive elements
<a href="/link">
  <a href="/nested">Nested link</a> // Not allowed!
</a>

<button>
  <button>Nested button</button> // Not allowed!
</button>
```

Source: `debug/src/debug.js:429-439`

## PropTypes Checking

Debug mode automatically checks PropTypes when defined on components:

```javascript theme={null}
import PropTypes from 'prop-types';

function MyComponent({ name, age }) {
  return <div>{name} is {age} years old</div>;
}

MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired
};

// Error: Failed prop type: Invalid prop `age` of type `string` 
// supplied to `MyComponent`, expected `number`
<MyComponent name="John" age="25" />
```

Source: `debug/src/debug.js:210-242`, `debug/src/check-props.js:24-54`

## Component Stack Traces

Debug mode provides detailed component stack traces showing where errors occurred:

```javascript theme={null}
function Parent() {
  return <Child />;
}

function Child() {
  return <Broken />; // Undefined component
}

// Error output includes:
//   in Child (at Child.js:5)
//   in Parent (at Parent.js:2)
```

### Enabling Source Locations

For detailed file and line information, add the Babel plugin:

```bash theme={null}
npm install --save-dev @babel/plugin-transform-react-jsx-source
```

```json theme={null}
// .babelrc
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx-source"]
  ]
}
```

<Note>
  Without the jsx-source plugin, stack traces will show component names but not file locations.
</Note>

Source: `debug/src/component-stack.js:78-100`

## Hook Validation

Debug mode validates hook usage:

### Hook Call Location

```javascript theme={null}
// Error: Hook can only be invoked from render methods
const [state, setState] = useState(0); // Outside component!

function MyComponent() {
  return <div>Valid</div>;
}
```

Source: `debug/src/debug.js:274-280`

### NaN in Dependencies

```javascript theme={null}
function MyComponent() {
  const value = NaN;
  
  useEffect(() => {
    // ...
  }, [value]); // Warning: Invalid argument passed to hook
  
  return <div>Component</div>;
}
```

Source: `debug/src/debug.js:470-490`

## Lifecycle Warnings

Debug mode warns about incorrect lifecycle usage:

### setState in Constructor

```javascript theme={null}
class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.setState({ foo: 'bar' }); // Warning!
    // Use: this.state = { foo: 'bar' }; instead
  }
}
```

Source: `debug/src/debug.js:494-511`

### forceUpdate on Unmounted Components

```javascript theme={null}
class MyComponent extends Component {
  componentWillUnmount() {
    setTimeout(() => {
      this.forceUpdate(); // Warning: memory leak!
    }, 1000);
  }
}

// Warning: Can't call "this.forceUpdate" on an unmounted component.
// This is a no-op, but it indicates a memory leak in your application.
```

Source: `debug/src/debug.js:528-546`

## Suspense Validation

Debug mode ensures Suspense boundaries are properly configured:

```javascript theme={null}
function MyComponent() {
  throw Promise.resolve(); // No Suspense boundary!
  return <div>Content</div>;
}

// Error: Missing Suspense. The throwing component was: MyComponent

// Fix: Wrap in Suspense
<Suspense fallback={<div>Loading...</div>}>
  <MyComponent />
</Suspense>
```

Source: `debug/src/debug.js:78-99`

## Duplicate Keys Warning

Debug mode detects duplicate keys in lists:

```javascript theme={null}
function List() {
  const items = ['a', 'b', 'a']; // Duplicate 'a'
  
  return (
    <ul>
      {items.map(item => (
        <li key={item}>{item}</li> // Warning!
      ))}
    </ul>
  );
}

// Warning: Following component has two or more children with the 
// same key attribute: "a". This may cause glitches and misbehavior 
// in rendering process.
```

Source: `debug/src/debug.js:446-468`

## Hydration Mismatch Detection

When using SSR with hydration, debug mode detects mismatches:

```javascript theme={null}
// Server renders:
<div>Server content</div>

// Client hydrates:
<span>Client content</span>

// Error: Expected a DOM node of type "span" but found "div" 
// as available DOM-node(s), this is caused by the SSR'd HTML 
// containing different DOM-nodes compared to the hydrated one.
```

Source: `debug/src/debug.js:582-590`

## Exported Utilities

The debug package exports several utilities for advanced use cases:

### resetPropWarnings()

Reset the history of PropTypes warnings (useful in tests):

```javascript theme={null}
import { resetPropWarnings } from 'preact/debug';

beforeEach(() => {
  resetPropWarnings();
});
```

Source: `debug/src/index.js:6`, `debug/src/check-props.js:8-10`

### Component Stack Utilities

```javascript theme={null}
import {
  captureOwnerStack,
  getCurrentVNode,
  getDisplayName,
  getOwnerStack,
  setupComponentStack
} from 'preact/debug';

// Get current rendering component
const vnode = getCurrentVNode();

// Get component name
const name = getDisplayName(vnode);

// Get full component stack
const stack = getOwnerStack(vnode);
```

Source: `debug/src/index.js:8-14`

## Disabling in Production

Always exclude debug from production builds:

### Webpack

```javascript theme={null}
// webpack.config.js
module.exports = {
  resolve: {
    alias: {
      'preact/debug': process.env.NODE_ENV === 'production' 
        ? 'preact/debug/noop' 
        : 'preact/debug'
    }
  }
};
```

### Vite

```javascript theme={null}
// vite.config.js
export default {
  resolve: {
    alias: {
      'preact/debug': process.env.NODE_ENV === 'production'
        ? 'preact/debug/noop'
        : 'preact/debug'
    }
  }
};
```

## Performance Impact

The debug addon adds significant overhead:

* Validates all vnodes before and after rendering
* Checks HTML nesting rules
* Validates PropTypes on every render
* Maintains component stack traces
* Adds \~10-20KB to bundle size

<Warning>
  Never ship debug mode to production. It will significantly slow down your application and increase bundle size.
</Warning>
