Error Handling
Stati implements a comprehensive error handling strategy designed to provide graceful failures, clear error messages, and robust recovery mechanisms. Understanding how Stati handles errors helps you debug issues and build more resilient sites.
Error Handling Philosophy
Stati follows these key principles:
- Graceful Degradation - Continue operation with fallback behavior when possible
- Clear Error Messages - All errors include actionable information
- Fail Fast - Configuration errors are caught early in the build process
- Recovery Mechanisms - Built-in fallbacks ensure partial builds can succeed
Error Categories
Configuration Errors
When they occur: During configuration loading and validation
Handling: Immediate failure with detailed error message
Common scenarios:
- Configuration file not found or unreadable
- Invalid configuration syntax (malformed JSON/JS)
- Missing required configuration fields
- Invalid configuration values
Error codes: CONFIG_NOT_FOUND, CONFIG_INVALID_SYNTAX, CONFIG_VALIDATION_FAILED
// Example: Invalid configuration
export default {
srcDir: 123, // ❌ Error: srcDir must be a string
isg: {
ttlSeconds: 'invalid' // ❌ Error: ttlSeconds must be a number
}
};
Content Loading Errors
When they occur: During content discovery and front matter parsing
Handling: Skip problematic files and continue with build
Common scenarios:
- Content directory not found or inaccessible
- Individual content files with invalid front matter
- File system permission errors
- Corrupted content files
Error codes: CONTENT_DIR_NOT_FOUND, FRONTMATTER_INVALID, FILE_READ_ERROR
---
title: My Post
date: invalid-date # ❌ Error: Invalid date format
draft # ❌ Error: Missing value for draft field
---
Template Rendering Errors
When they occur: During template processing and HTML generation
Handling: Use built-in fallback template
Common scenarios:
- Template file not found
- Template syntax errors
- Template rendering failures
- Missing template data
Error codes: TEMPLATE_NOT_FOUND, TEMPLATE_SYNTAX_ERROR, TEMPLATE_RENDER_ERROR
<!-- Template syntax error -->
<% if (stati.collection?.pages { %> <!-- ❌ Missing closing parenthesis -->
<ul>
<% stati.collection.pages.forEach(page => { %>
<li><%= page.title %></li>
<% }); %>
</ul>
<% } %>
File System Errors
When they occur: During output file writing and static asset copying
Handling: Immediate failure (critical for build success)
Common scenarios:
- Output directory permission errors
- Disk space exhausted
- File system corruption
- Directory creation failures
Error codes: PERMISSION_DENIED, DISK_SPACE_FULL, OUTPUT_DIR_ERROR
Build Hook Errors
When they occur: During execution of user-defined build hooks
Handling: Immediate failure (hooks are user-controlled)
Common scenarios:
- Hook function throws an exception
- Async hook rejection
- Hook timeout
Error codes: HOOK_BEFORE_ALL_FAILED, HOOK_AFTER_ALL_FAILED, HOOK_BEFORE_RENDER_FAILED, HOOK_AFTER_RENDER_FAILED
export default defineConfig({
hooks: {
beforeRender: async (ctx) => {
throw new Error('Hook failed'); // ❌ Will stop the build
}
}
});
StatiError Class
Stati uses a structured error class for consistent error handling:
class StatiError extends Error {
constructor(
public code: string,
message: string,
public details?: Record<string, unknown>
) {
super(message);
this.name = 'StatiError';
}
}
Error Code Patterns
Error codes follow consistent naming:
- CONFIG_ - Configuration-related errors
- CONTENT_ - Content loading and processing errors
- TEMPLATE_ - Template rendering errors
- FILE_ - File system operation errors
- HOOK_ - Build hook execution errors
- ISG_ - Incremental Static Generation errors
Fallback Mechanisms
Template Fallback
When template rendering fails, Stati uses a built-in fallback:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{page.title}</title>
<meta name="description" content="{page.description}">
</head>
<body>
<main>{rendered_content}</main>
</body>
</html>
Content Fallback
When markdown processing fails:
- Original content is wrapped in
<pre>tags - HTML is properly escaped for safety
- Build continues with fallback content
Navigation Fallback
If navigation building fails:
- Empty navigation array is provided to templates
- Site remains functional without navigation
- Error is logged but build continues
Error Reporting
Console Output
Stati uses colored console output:
- 🔴 Errors: Red text, logged to stderr
- 🟡 Warnings: Yellow text, logged to stdout
- ℹ️ Info: Standard text, logged to stdout
Error Context
Error messages include relevant context:
Error rendering layout /blog/layout.eta for page /blog/my-post/:
Template syntax error: Unexpected token 'if' at line 15
Build Statistics
Errors are tracked in build statistics:
interface BuildStats {
pages: number;
assets: number;
errors: number;
warnings: number;
criticalErrors: string[];
buildTime: number;
}
Debugging Approaches
1. Isolate the Problem
Build with subset of content:
# Move most content out temporarily
mv site/blog site/blog-backup
stati build
Check configuration:
# Test configuration loading
node -e "console.log(require('./stati.config.js'))"
2. Use Verbose Logging
Enable detailed output:
DEBUG=stati:* stati build
Check specific components:
DEBUG=stati:templates stati build
DEBUG=stati:content stati build
3. Common Error Scenarios
Build fails immediately:
- ✅ Check configuration file syntax
- ✅ Verify directory permissions
- ✅ Ensure required directories exist
Some pages missing from output:
- ✅ Check for
draft: truein front matter - ✅ Verify content directory structure
- ✅ Look for template resolution errors
Template rendering issues:
- ✅ Verify template syntax in isolation
- ✅ Check template data availability
- ✅ Review template file permissions
Best Practices
1. Validate Configuration
Test your configuration in development:
// stati.config.js
import { defineConfig } from '@stati/core';
export default defineConfig({
// Configuration with TypeScript validation
site: {
title: 'My Site',
baseUrl: process.env.NODE_ENV === 'production'
? 'https://mysite.com'
: 'http://localhost:3000'
}
});
2. Handle Hook Errors Gracefully
export default defineConfig({
hooks: {
beforeRender: async (ctx) => {
try {
// Your hook logic
await processExternalData();
} catch (error) {
console.error('Hook failed:', error);
// Decide whether to continue or fail
throw error; // Re-throw to stop build
}
}
}
});
3. Test Content Incrementally
Gradual rollout approach:
- Test with a subset of content first
- Use
--include-draftsflag for testing - Monitor error output during builds
- Fix issues before expanding content
4. Use Consistent Front Matter
Establish a schema:
---
title: string (required)
description: string (required)
date: YYYY-MM-DD (required)
draft: boolean (optional)
tags: string[] (optional)
---
Recovery Strategies
Partial Build Success
Stati attempts to build as many pages as possible:
- ✅ Identify problematic content incrementally
- ✅ Deploy partial updates while fixing issues
- ✅ Maintain site functionality during updates
Build Interruption Recovery
If a build is interrupted:
- Cache preservation:
.statidirectory preserves progress - Atomic operations: Static assets copied atomically
- Clean state: Subsequent builds resume cleanly
Cache-Related Issues
Clear cache when encountering:
# Clear all cache
stati build --clean
# Force complete rebuild
stati build --force
# Clear and rebuild
stati build --clean --force
Development Workflow
1. Start with Clean Build
# Ensure clean starting point
stati build --clean --verbose
2. Monitor Development Server
# Watch for errors in development
stati dev --verbose
3. Test Production Build
# Test production build before deployment
NODE_ENV=production stati build
4. Validate Output
# Check generated files
ls -la dist/
# Verify critical pages exist
test -f dist/index.html && echo "✅ Homepage exists"
Understanding Stati’s error handling helps you build more reliable sites and debug issues more effectively. Combined with proper configuration validation and incremental testing, you can maintain robust build processes even with complex content structures.