This guide helps you diagnose and resolve common issues with Adaptly. If you're experiencing problems, check this guide first before seeking additional help.
Error: Component type MetricCard not found in registry
Causes:
- Component not properly exported
- Component not registered in AdaptlyProvider
- Component name mismatch between code and registry
Solutions:
- Check component export:
// ✅ Correct export
export function MetricCard(props: MetricCardProps) {
return <div>...</div>;
}
// ❌ Incorrect export
export default function MetricCard(props: MetricCardProps) {
return <div>...</div>;
}- Check component registration:
// ✅ Correct registration
<AdaptlyProvider
components={{ MetricCard, SalesChart, DataTable }}
// ... other props
/>
// ❌ Incorrect registration
<AdaptlyProvider
components={{ metricCard: MetricCard }} // Wrong key
// ... other props
/>- Check adaptly.json configuration:
{
"components": {
"MetricCard": { // Must match component name
"description": "Display key performance indicators",
// ... other config
}
}
}Error: API key not found or Invalid API key
Causes:
- Environment variable not set
- Wrong environment variable name
- Invalid API key
- API key not accessible
Solutions:
- Check environment variable:
# .env.local (Next.js)
NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY=your_api_key_here
# .env (React)
REACT_APP_GOOGLE_GENERATIVE_AI_API_KEY=your_api_key_here- Verify variable name:
// ✅ Correct usage
<AdaptlyProvider
apiKey={process.env.NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY!}
// ... other props
/>
// ❌ Incorrect usage
<AdaptlyProvider
apiKey={process.env.GOOGLE_API_KEY!} // Wrong variable name
// ... other props
/>- Test API key:
// Test API key validity
const testApiKey = async () => {
try {
const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models', {
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_GOOGLE_GENERATIVE_AI_API_KEY}`
}
});
console.log('API key valid:', response.ok);
} catch (error) {
console.error('API key test failed:', error);
}
};Error: Storage not working or Data not persisting
Causes:
- localStorage disabled
- Storage quota exceeded
- Version mismatch
- Invalid data format
Solutions:
- Check localStorage availability:
const checkLocalStorage = () => {
try {
localStorage.setItem('test', 'test');
localStorage.removeItem('test');
console.log('localStorage is available');
return true;
} catch (error) {
console.error('localStorage not available:', error);
return false;
}
};- Check storage quota:
const checkStorageQuota = async () => {
if ('storage' in navigator && 'estimate' in navigator.storage) {
const estimate = await navigator.storage.estimate();
console.log('Storage quota:', estimate.quota);
console.log('Storage usage:', estimate.usage);
console.log('Available space:', estimate.quota - estimate.usage);
}
};- Handle version mismatch:
// Clear storage on version mismatch
const handleVersionMismatch = () => {
const currentVersion = '2.0.0';
const storedVersion = localStorage.getItem('my-app-ui_version');
if (storedVersion && storedVersion !== currentVersion) {
console.log('Version mismatch detected, clearing storage');
localStorage.removeItem('my-app-ui_1.0.0');
localStorage.removeItem('my-app-ui_2.0.0');
}
};Error: LLM processing failed or AI not responding
Causes:
- Network issues
- API rate limits
- Invalid model name
- Insufficient API credits
Solutions:
- Check network connectivity:
const checkNetwork = async () => {
try {
const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models');
console.log('Network connectivity:', response.ok);
} catch (error) {
console.error('Network error:', error);
}
};- Handle rate limits:
const handleRateLimit = (error: Error) => {
if (error.message.includes('rate limit')) {
console.log('Rate limit exceeded, waiting...');
setTimeout(() => {
// Retry request
}, 60000); // Wait 1 minute
}
};- Check model availability:
const checkModelAvailability = async (provider: string, model: string) => {
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}`);
console.log('Model available:', response.ok);
} catch (error) {
console.error('Model not available:', error);
}
};Error: Component not rendering or Empty components
Causes:
- Invalid component props
- Missing required props
- Component validation failures
- Empty or invalid data
Solutions:
- Validate component props:
const validateComponentProps = (component: UIComponent, config: ComponentJsonConfig) => {
const requiredProps = Object.entries(config.props)
.filter(([_, propConfig]) => propConfig.required)
.map(([name, _]) => name);
for (const prop of requiredProps) {
if (!component.props[prop]) {
console.error(`Missing required prop: ${prop}`);
return false;
}
}
return true;
};- Check component data:
const checkComponentData = (component: UIComponent) => {
if (component.type === 'MetricCard') {
const { title, value } = component.props;
if (!title || !value || value === '$0' || value === '0') {
console.warn('Invalid metric card data:', component.props);
return false;
}
}
return true;
};- Debug component rendering:
const debugComponentRendering = (component: UIComponent) => {
console.log('Rendering component:', component.type);
console.log('Component props:', component.props);
console.log('Component position:', component.position);
console.log('Component visible:', component.visible);
};<AdaptlyProvider
// ... other props
logging={{ enabled: true, level: 'debug' }}
/>function ComponentInspector() {
const { adaptation } = useAdaptiveUI();
return (
<div className="p-4 bg-gray-100 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Component Inspector</h3>
<div className="space-y-2">
{adaptation.components.map(component => (
<div key={component.id} className="p-2 bg-white rounded border">
<div className="flex justify-between items-start">
<div>
<p className="font-medium">{component.type}</p>
<p className="text-sm text-gray-600">ID: {component.id}</p>
<p className="text-sm text-gray-600">
Position: {component.position.x}, {component.position.y}
({component.position.w}x{component.position.h})
</p>
</div>
<div className="text-sm text-gray-500">
{component.visible ? 'Visible' : 'Hidden'}
</div>
</div>
<div className="mt-2">
<p className="text-xs text-gray-500">Props:</p>
<pre className="text-xs bg-gray-50 p-2 rounded">
{JSON.stringify(component.props, null, 2)}
</pre>
</div>
</div>
))}
</div>
</div>
);
}function StorageInspector() {
const { hasStoredData, loadFromStorage } = useAdaptiveUI();
const [storageData, setStorageData] = useState<any>(null);
const inspectStorage = () => {
if (hasStoredData()) {
const data = loadFromStorage();
setStorageData(data);
}
};
return (
<div className="p-4 bg-gray-100 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Storage Inspector</h3>
<button
onClick={inspectStorage}
className="px-4 py-2 bg-blue-500 text-white rounded mb-4"
>
Inspect Storage
</button>
{storageData && (
<div className="bg-white p-4 rounded border">
<pre className="text-sm overflow-auto">
{JSON.stringify(storageData, null, 2)}
</pre>
</div>
)}
</div>
);
}function PerformanceMonitor() {
const [metrics, setMetrics] = useState({
renderTime: 0,
componentCount: 0,
memoryUsage: 0
});
useEffect(() => {
const startTime = performance.now();
// Measure render time
const endTime = performance.now();
const renderTime = endTime - startTime;
// Measure memory usage
const memoryUsage = (performance as any).memory?.usedJSHeapSize || 0;
setMetrics({
renderTime,
componentCount: document.querySelectorAll('[data-adaptly-component]').length,
memoryUsage
});
}, []);
return (
<div className="p-4 bg-gray-100 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Performance Monitor</h3>
<div className="grid grid-cols-3 gap-4">
<div>
<p className="text-sm text-gray-600">Render Time</p>
<p className="text-lg font-semibold">{metrics.renderTime.toFixed(2)}ms</p>
</div>
<div>
<p className="text-sm text-gray-600">Components</p>
<p className="text-lg font-semibold">{metrics.componentCount}</p>
</div>
<div>
<p className="text-sm text-gray-600">Memory</p>
<p className="text-lg font-semibold">{(metrics.memoryUsage / 1024 / 1024).toFixed(2)}MB</p>
</div>
</div>
</div>
);
}function ResetButton() {
const { resetToDefault, clearStorage } = useAdaptiveUI();
const handleReset = () => {
resetToDefault();
clearStorage();
console.log('Reset to default state');
};
return (
<button
onClick={handleReset}
className="px-4 py-2 bg-red-500 text-white rounded"
>
Reset to Default
</button>
);
}function ClearStorageButton() {
const { clearStorage } = useAdaptiveUI();
const handleClear = () => {
const success = clearStorage();
if (success) {
console.log('Storage cleared successfully');
} else {
console.error('Failed to clear storage');
}
};
return (
<button
onClick={handleClear}
className="px-4 py-2 bg-yellow-500 text-white rounded"
>
Clear Storage
</button>
);
}function ReloadComponentsButton() {
const { loadFromStorage } = useAdaptiveUI();
const handleReload = () => {
const savedData = loadFromStorage();
if (savedData) {
console.log('Components reloaded from storage');
} else {
console.log('No saved data to reload');
}
};
return (
<button
onClick={handleReload}
className="px-4 py-2 bg-green-500 text-white rounded"
>
Reload Components
</button>
);
}class AdaptlyErrorBoundary extends React.Component {
constructor(props: any) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: any) {
console.error('Adaptly Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<h3 className="text-lg font-semibold text-red-800">Something went wrong</h3>
<p className="text-red-600 mt-2">
{this.state.error?.message || 'An unexpected error occurred'}
</p>
<button
onClick={() => this.setState({ hasError: false, error: null })}
className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
>
Try Again
</button>
</div>
);
}
return this.props.children;
}
}
// Use with AdaptlyProvider
<AdaptlyErrorBoundary>
<AdaptlyProvider
// ... props
/>
</AdaptlyErrorBoundary>function ErrorRecovery() {
const { resetToDefault, clearStorage } = useAdaptiveUI();
const [error, setError] = useState<Error | null>(null);
const handleError = (error: Error) => {
console.error('Adaptly error:', error);
setError(error);
};
const recoverFromError = () => {
try {
resetToDefault();
clearStorage();
setError(null);
console.log('Recovered from error');
} catch (recoveryError) {
console.error('Recovery failed:', recoveryError);
}
};
if (error) {
return (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<h3 className="text-lg font-semibold text-red-800">Error Detected</h3>
<p className="text-red-600 mt-2">{error.message}</p>
<button
onClick={recoverFromError}
className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
>
Recover
</button>
</div>
);
}
return null;
}- Installation Guide - Setup issues
- Quick Start Guide - Basic usage
- Component Registry Guide - Component configuration
- LLM Providers Guide - AI provider issues
- Storage Service Guide - Storage issues
- Advanced Features Guide - Advanced configurations
When reporting issues, include:
function DebugInfo() {
const { adaptation, config, currentLLMProvider } = useAdaptiveUI();
const debugInfo = {
version: '1.0.0',
components: adaptation.components.length,
layout: adaptation.layout,
llmProvider: currentLLMProvider,
storageEnabled: config?.storage?.enabled,
storageKey: config?.storage?.key,
storageVersion: config?.storage?.version,
userAgent: navigator.userAgent,
localStorage: typeof localStorage !== 'undefined',
timestamp: new Date().toISOString()
};
return (
<div className="p-4 bg-gray-100 rounded-lg">
<h3 className="text-lg font-semibold mb-4">Debug Information</h3>
<pre className="text-sm overflow-auto">
{JSON.stringify(debugInfo, null, 2)}
</pre>
</div>
);
}- GitHub Issues: Report bugs and request features
- GitHub Discussions: Ask questions and share ideas
- Documentation: Check this comprehensive guide
- Examples: Look at the demo application in
/examples
| Issue | Solution |
|---|---|
| Component not found | Check export and registration |
| API key error | Verify environment variable |
| Storage not working | Check localStorage availability |
| AI not responding | Verify API key and model |
| Performance issues | Enable memoization and debouncing |
| Version conflicts | Clear storage and update version |
- Always validate component props
- Use TypeScript for type safety
- Test with different providers
- Monitor performance metrics
- Handle errors gracefully
- Keep documentation updated
// Test component registration
const testComponentRegistration = () => {
const components = { MetricCard, SalesChart, DataTable };
const componentNames = Object.keys(components);
console.log('Registered components:', componentNames);
};
// Test API key
const testApiKey = async () => {
try {
const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models');
console.log('API key test:', response.ok);
} catch (error) {
console.error('API key test failed:', error);
}
};
// Test storage
const testStorage = () => {
try {
localStorage.setItem('test', 'test');
localStorage.removeItem('test');
console.log('Storage test: passed');
} catch (error) {
console.error('Storage test failed:', error);
}
};// Monitor component changes
useEffect(() => {
console.log('Components changed:', adaptation.components.length);
}, [adaptation.components]);
// Monitor AI processing
useEffect(() => {
if (isLLMProcessing) {
console.log('AI processing started');
} else {
console.log('AI processing completed');
}
}, [isLLMProcessing]);
// Monitor storage
useEffect(() => {
console.log('Storage status:', hasStoredData());
}, [hasStoredData]);Still having issues? Check out the GitHub Issues or GitHub Discussions for community support!