Advanced scenarios, edge cases, and comprehensive error handling patterns.
Error: ConfigMissingError - components.json not found
import { getRegistryItems, ConfigMissingError } from 'shadcn/registry';
try {
const items = await getRegistryItems(['@shadcn/button']);
} catch (error) {
if (error instanceof ConfigMissingError) {
// Solution: Initialize project
console.error('Project not initialized. Run: npx shadcn init');
}
}CLI Exit Code: 2
# Error: components.json not found
# Solution: Run npx shadcn init first
npx shadcn initError: RegistryNotFoundError - Item not found in registry
import { getRegistryItems, RegistryNotFoundError } from 'shadcn/registry';
import { searchRegistries } from 'shadcn/registry';
try {
const items = await getRegistryItems(['@shadcn/nonexistent']);
} catch (error) {
if (error instanceof RegistryNotFoundError) {
// Try to find similar items
const searchResults = await searchRegistries(['@shadcn'], {
query: 'nonexistent',
limit: 5
});
if (searchResults.items.length > 0) {
console.log('Did you mean:', searchResults.items.map(i => i.name).join(', '));
}
}
}CLI Exit Code: 3
# Error: Component not found in registry
# Solution: Search for correct component name
npx shadcn search @shadcn --query buttonError: RegistryNotConfiguredError - Registry not in components.json
import { getRegistryItems, RegistryNotConfiguredError } from 'shadcn/registry';
try {
const items = await getRegistryItems(['@custom/button']);
} catch (error) {
if (error instanceof RegistryNotConfiguredError) {
// Solution: Add registry to components.json
console.error(`Registry not configured: ${error.context?.registry}`);
if (error.suggestion) {
console.log('Suggestion:', error.suggestion);
}
}
}CLI Exit Code: 3
Error: RegistryFetchError - Network or fetch errors
import { getRegistryItems, RegistryFetchError } from 'shadcn/registry';
async function fetchWithRetry(items: string[], maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await getRegistryItems(items);
} catch (error) {
if (error instanceof RegistryFetchError && attempt < maxRetries) {
// Wait before retry (exponential backoff)
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
throw error;
}
}
}CLI Exit Code: 3
Error: RegistryUnauthorizedError - Authentication required
import { getRegistryItems, RegistryUnauthorizedError } from 'shadcn/registry';
try {
const items = await getRegistryItems(['@private/button']);
} catch (error) {
if (error instanceof RegistryUnauthorizedError) {
// Check for missing environment variables
console.error('Authentication required. Check registry configuration and ensure required environment variables are set.');
console.error('Missing variables:', error.context);
}
}CLI Exit Code: 3
When adding multiple components, some may fail:
import { getRegistryItems, RegistryNotFoundError } from 'shadcn/registry';
async function batchGetItems(itemNames: string[]) {
const results: Array<{ name: string; item?: any; error?: string }> = [];
// Process items individually to handle partial failures
for (const itemName of itemNames) {
try {
const [item] = await getRegistryItems([itemName]);
results.push({ name: itemName, item });
} catch (error) {
if (error instanceof RegistryNotFoundError) {
results.push({ name: itemName, error: `Not found: ${error.message}` });
} else {
results.push({ name: itemName, error: `Error: ${error.message}` });
}
}
}
return results;
}CLI Behavior: When adding multiple components, if one fails, the command may partially succeed. Check output for individual component status.
Error: Circular dependency detected
import { resolveRegistryItems } from 'shadcn';
import { RegistryError } from 'shadcn/registry';
async function safeResolveItems(items: string[]) {
try {
return await resolveRegistryItems(items);
} catch (error) {
if (error instanceof RegistryError && error.code === 'VALIDATION_ERROR') {
if (error.message.includes('circular') || error.message.includes('dependency')) {
throw new Error(
`Circular dependency detected in registry items: ${items.join(', ')}. ` +
`This usually indicates a registry configuration issue.`
);
}
}
throw error;
}
}CLI Exit Code: 4
When adding a component that already exists:
# Without --overwrite flag, command will prompt
npx shadcn add button
# With --overwrite flag, overwrites without prompting
npx shadcn add button --yes --overwriteCLI Exit Code: 0 (with prompt) or 0 (with --overwrite)
Error: Validation error - Invalid component name
// Invalid: Missing registry prefix
await getRegistryItems(['button']); // May work if default registry configured
// Valid: With registry prefix
await getRegistryItems(['@shadcn/button']);
// Invalid: Malformed name
await getRegistryItems(['@shadcn/']); // Validation errorCLI Exit Code: 4
Configuration discovery searches parent directories:
import { getRegistriesConfig } from 'shadcn';
import { findUp } from 'find-up';
import { dirname } from 'path';
// Works even if components.json is in parent directory
const configPath = await findUp('components.json', { cwd: process.cwd() });
const configDir = dirname(configPath);
const { registries } = await getRegistriesConfig(configDir);Handle multiple components.json files:
import { getRegistriesConfig } from 'shadcn';
import { findUp } from 'find-up';
import { dirname } from 'path';
async function getWorkspaceConfigs(rootDir: string) {
const configs: Array<{ path: string; config: any }> = [];
let currentDir = rootDir;
while (currentDir) {
const configPath = await findUp('components.json', { cwd: currentDir });
if (configPath) {
const configDir = dirname(configPath);
const { registries } = await getRegistriesConfig(configDir);
configs.push({ path: configPath, config: { registries } });
const parentDir = dirname(configDir);
if (parentDir === currentDir) break;
currentDir = parentDir;
} else {
break;
}
}
return configs;
}CLI Exit Code: 1
# Error: Package manager (npm/yarn/pnpm) not found
# Solution: Ensure package manager is installed and in PATH
which npm
# or
which yarn
# or
which pnpmCLI Exit Code: 1
# Error: Permission denied when writing files
# Solution: Check file system permissions
chmod -R u+w components/Handle network timeouts gracefully:
import { getRegistryItems, RegistryFetchError } from 'shadcn/registry';
async function fetchWithTimeout(items: string[], timeoutMs = 5000) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Request timeout')), timeoutMs);
});
try {
return await Promise.race([
getRegistryItems(items),
timeoutPromise
]);
} catch (error) {
if (error instanceof RegistryFetchError) {
throw new Error(`Network error: ${error.message}`);
}
throw error;
}
}import {
getRegistryItems,
RegistryError,
RegistryNotFoundError,
RegistryNotConfiguredError,
ConfigMissingError,
RegistryFetchError,
RegistryUnauthorizedError
} from 'shadcn/registry';
import { searchRegistries } from 'shadcn/registry';
async function safeGetRegistryItems(items: string[]) {
try {
return await getRegistryItems(items);
} catch (error) {
if (error instanceof ConfigMissingError) {
throw new Error('Project not initialized. Run: npx shadcn init');
} else if (error instanceof RegistryNotConfiguredError) {
throw new Error(`Registry not configured. Add to components.json: ${error.suggestion}`);
} else if (error instanceof RegistryNotFoundError) {
// Try to find similar items
const searchTerm = items[0].split('/').pop() || items[0];
const searchResults = await searchRegistries(['@shadcn'], {
query: searchTerm,
limit: 5
});
if (searchResults.items.length > 0) {
throw new Error(
`Item not found: ${items[0]}. Did you mean: ${searchResults.items.map(i => i.addCommandArgument).join(', ')}?`
);
}
throw new Error(`Item not found: ${items[0]}. Try: npx shadcn search ${searchTerm}`);
} else if (error instanceof RegistryUnauthorizedError) {
throw new Error(
`Authentication required. Check registry configuration and ensure required environment variables are set.`
);
} else if (error instanceof RegistryFetchError) {
throw new Error(`Network error: ${error.message}. Please check your connection and try again.`);
} else if (error instanceof RegistryError) {
throw new Error(`Registry error: ${error.code} - ${error.message}`);
}
throw error;
}
}| Exit Code | Meaning | Common Causes |
|---|---|---|
| 0 | Success | Operation completed successfully |
| 1 | General error | File system, network, package manager errors |
| 2 | Configuration error | Missing or invalid components.json |
| 3 | Registry error | Item not found, network error, authentication failure |
| 4 | Validation error | Invalid input, circular dependency |
See CLI Commands Reference for complete exit code documentation.