Troubleshooting
Common issues and solutions when building custom visuals
"Element type is invalid" Error
This is the most common error. It occurs when component names don't match across files.
Symptom:
Error: Element type is invalid. Received a promise that resolves to: undefined.
Lazy element type must resolve to a class or function.Cause: Name mismatch between configuration and exports.
Example of the problem:
// components.config.ts
{ component: 'RevenueChart' } // Expects 'RevenueChart'
// index.ts
export { RevenueChart } from '...'; // Exports 'RevenueChart'
// revenue-chart.tsx
export function MyRevenueChart() { } // Wrong! Exports 'MyRevenueChart'Fix: Ensure all three names match exactly:
// components.config.ts
{ component: 'RevenueChart' }
// index.ts
export { RevenueChart } from './semaphor-components/revenue-chart/revenue-chart';
// revenue-chart.tsx
export function RevenueChart() { } // Correct!Checklist when renaming components:
- Function name in
.tsxfile - Export in
index.ts -
componentfield incomponents.config.ts - Key in
sample-data-registry.ts - Run
npm run build
Component Not Appearing in Semaphor
- Verify export: Is the component exported in
index.ts? - Check config: Is it registered in
components.config.ts? - Verify names match: Does
componentexactly match the exported function name? - Rebuild and republish:
npm run build && semaphor publish - Hard refresh: Clear browser cache and reload Semaphor
Data is Empty
- Configure data source: Ensure the card has a data source in Semaphor
- Check column names: Verify you're accessing correct column names
- Add debugging:
console.log('data:', data)to inspect - Handle empty state: Always check
if (!data || data.length === 0)
Debug pattern:
export function MyVisual({ data }: SingleInputVisualProps) {
// Add this temporarily to debug
console.log('Data received:', data);
console.log('Columns:', data?.[0] ? Object.keys(data[0]) : 'no data');
if (!data?.length) {
return <div>No data available</div>;
}
// ...rest of component
}Inline Filters Not Showing
- Default to
[]: EnsureinlineFilters = []in props destructuring - Check conditional: Use
inlineFilters.length > 0before rendering - Configure in Semaphor: Inline filters must be added to the card in Semaphor's visual editor
Correct pattern:
export function MyVisual({
data,
inlineFilters = [] // Always provide default
}: SingleInputVisualProps) {
return (
<div>
{inlineFilters.length > 0 && (
<div className="flex gap-2 p-3 bg-muted/30 rounded-lg">
{inlineFilters}
</div>
)}
{/* ...rest of visual */}
</div>
);
}Styling Issues
CSS Not Loading
- Import CSS: Verify
../index.cssis imported inindex.ts - Check build output: Ensure
dist/style.cssexists after build
Tailwind Classes Not Working
All Tailwind utilities are available. If classes aren't applying:
- Check for typos in class names
- Ensure you're not overriding with inline styles
- Check CSS specificity issues
Theme Colors Not Applying
- Use theme prop: Access colors via
theme?.colors - Provide fallbacks: Always have fallback colors
const primaryColor = theme?.colors?.[0] || '#3b82f6';
const isDarkMode = theme?.mode === 'dark';Dark Mode Issues
Use conditional styling based on theme?.mode:
<div className={theme?.mode === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'}>
...
</div>Or use Tailwind's dark mode classes (if configured):
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
...
</div>Showcase Not Showing Component
- Check registry: Is the component registered in
sample-data-registry.ts? - Verify key: The registry key must match the component name exactly
- Check data file: Ensure
.data.tsexportssampleData
Registry format:
// sample-data-registry.ts
import * as myVisualData from '../components/semaphor-components/my-visual/my-visual.data';
export const sampleDataRegistry = {
MyVisual: myVisualData, // Key must match component name
};Data file format:
// my-visual.data.ts
export const sampleData = [
{ column1: 'value1', column2: 100 },
{ column1: 'value2', column2: 200 },
];
export const sampleSettings = {
title: 'My Visual',
};
export const sampleTheme = {
colors: ['#3b82f6', '#10b981'],
mode: 'light' as const,
};Build Errors
Clean Rebuild
rm -rf dist node_modules
npm install
npm run buildTypeScript Errors
Run type checking independently:
npx tsc --noEmitMissing Dependencies
If you're using external libraries:
npm install [library-name]Then verify it's included in the bundle by checking dist/index.js size.
Publishing Issues
"Unauthorized" Error
- Verify your project credentials in
semaphor.json - Re-run
semaphor initto update credentials - Check that your Semaphor project ID matches
Plugin Not Updating
- Increment version in
package.json - Rebuild:
npm run build - Republish:
semaphor publish - Hard refresh Semaphor dashboard (Ctrl+Shift+R)
Manifest Not Generated
The manifest is generated from components.config.ts during build. Ensure:
components.config.tshas valid syntax- All registered components are exported in
index.ts - Build completes without errors
Performance Issues
Component Re-rendering Too Often
Use useMemo for expensive calculations:
const processedData = useMemo(() => {
return data.map(row => /* expensive transformation */);
}, [data]);Large Dataset Handling
For datasets over 1000 rows:
- Consider virtualization (react-virtual, react-window)
- Paginate on the server side
- Aggregate data in SQL before sending to the visual
Multi-Input Visual Issues
Data Not Loading for All Slots
- Check that all slot cards have valid data sources
- Verify
dataInputCardIdsmapping is correct - Ensure the source cards exist on the dashboard
CardMetadata Array Empty
Multi-input visuals receive an array of metadata. Check the array length:
export function MyMultiInput({ data, cardMetadata }: MultiInputVisualProps) {
console.log('Metadata array:', cardMetadata);
console.log('Data array length:', data?.length);
// cardMetadata[0] = first slot's metadata
// cardMetadata[1] = second slot's metadata
// etc.
}See the Multi-Input Guide for detailed troubleshooting.
Self-Hosted Plugin Issues
If you're running Semaphor self-hosted, publishing and loading custom visuals requires additional configuration. See the Self-Hosted Custom Visuals guide for setup instructions.
"503 -- Custom plugin storage is not configured"
This means APPS_BUCKET_NAME is not set in your semaphor.env. Add it and restart containers.
Plugin publish fails with connection error
When running semaphor publish, ensure you are targeting your self-hosted instance:
semaphor publish --host https://your-semaphor-domain.comOr set the host during semaphor init or via the SEMAPHOR_API_URL environment variable.
Getting Help
If you're still stuck:
- Check browser console: Look for JavaScript errors
- Check network tab: Verify plugin bundle is loading
- Simplify: Start with a minimal component and add complexity
- Contact support: support@semaphor.cloud