Troubleshooting Common Issues
This guide helps you diagnose and fix common issues when deploying and running applications on the Strongly platform.
Build Failures
Build Timeout (20 minutes)
Problem: Build exceeds 20-minute timeout limit
Symptoms:
- Build status changes to
timeout - Build logs show timeout error
- Large dependencies downloading
- Complex build steps
Solutions:
- Optimize Docker build:
# Use .dockerignore to exclude unnecessary files
node_modules
.git
*.log
# Use multi-stage builds
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:18-alpine
COPY /app/dist ./dist
- Leverage layer caching:
# Copy package files first (changes less often)
COPY package*.json ./
RUN npm ci
# Copy code last (changes more often)
COPY . .
- Reduce dependencies:
// Remove unnecessary devDependencies
{
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {}
}
Build Status Flow
Builds progress through these statuses:
pending -> building -> completed (success)
-> failed (build error)
-> cancelled (user cancelled)
-> timeout (exceeded 20 minutes)
App Builder Unreachable
Problem: Cannot connect to the app builder service
Symptoms:
- Error:
app-builder-unreachable - Error:
Cannot connect to app builder service - Deployment fails before build starts
Solutions:
- Check service status: The app-builder backend may be down or restarting
- Retry deployment: Wait a moment and try again
- Check network: Ensure the frontend can reach the backend URL configured in settings
- Check logs: Look at the server logs for connection errors
Dockerfile Syntax Errors
Problem: Invalid Dockerfile syntax
Symptoms:
- Build fails immediately
- Error: "Dockerfile parse error"
Common Issues:
# Bad: Missing WORKDIR
COPY . .
# Good: Set WORKDIR first
WORKDIR /app
COPY . .
# Bad: Wrong order (FROM must be first)
RUN apt-get update
FROM node:18
# Good: FROM first
FROM node:18
RUN apt-get update
# Bad: Missing quotes for paths with spaces
COPY my folder /app
# Good: Quote paths
COPY "my folder" /app
Solution: Validate Dockerfile locally before deploying:
docker build -t test .
Missing Files in Build Context
Problem: Files not found during build
Symptoms:
COPYcommand fails- Module not found errors
Solutions:
- Check archive structure:
# Dockerfile and manifest must be in root
app.tar.gz
├── Dockerfile
├── strongly.manifest.yaml
├── package.json
└── src/
- Verify .dockerignore isn't excluding needed files:
# Don't ignore required files
!package.json
!src/
- Use correct COPY paths:
# Relative to build context root
COPY package.json ./
COPY src/ ./src/
Stale Builds
Problem: Old builds lingering in pending or building state
Solutions:
- Check if the build is still actively running
- If stuck, the platform has a stale build cleanup endpoint that can be triggered by administrators
- Create a new deployment which will start a fresh build
Application Startup Issues
Health Check Failures
Problem: App deployed but health checks fail
Symptoms:
- Status shows "Unhealthy"
- Pods continuously restart
- "CrashLoopBackOff" status
Solutions:
- Implement health check endpoint:
// Express.js
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});
- Verify health check path in manifest:
health_check:
path: /health # Must match your endpoint
port: 3000
initial_delay: 15 # Give app time to start
- Increase startup timeout (in manifest
runtimesection):
runtime:
startup_timeout: 120 # Give more time for slow-starting apps
- Check application logs:
Navigate to app details -> Logs tab
Look for startup errors
- Test locally:
docker run -p 3000:3000 my-app
curl http://localhost:3000/health
Port Binding Errors
Problem: Application fails to start due to port conflicts
Symptoms:
- "Port already in use"
- "EADDRINUSE" error
- App crashes on startup
Solutions:
- Match port in code and manifest:
// server.js
const PORT = process.env.PORT || 3000;
app.listen(PORT);
# manifest
ports:
- port: 3000
expose: true
- Use PORT environment variable:
// Always use environment variable
const PORT = process.env.PORT;
if (!PORT) {
throw new Error('PORT environment variable not set');
}
Missing Environment Variables
Problem: App crashes due to missing configuration
Symptoms:
- "Environment variable not defined"
- "Cannot read property of undefined"
- Database connection errors
Solutions:
- Check STRONGLY_SERVICES is parsed correctly:
const data = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const services = data.services || {};
// Check addons
const mongoAddons = services.addons?.mongodb || [];
if (mongoAddons.length === 0) {
throw new Error('No MongoDB addon configured');
}
- Provide default values:
const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
const TIMEOUT = parseInt(process.env.TIMEOUT || '30000');
- Validate required variables on startup:
const required = ['DATABASE_URL', 'JWT_SECRET'];
const missing = required.filter(v => !process.env[v]);
if (missing.length > 0) {
throw new Error(`Missing required env vars: ${missing.join(', ')}`);
}
- Check manifest configuration:
env:
- name: DATABASE_URL
value: ""
required: true # Platform will enforce this
secret: true
Out of Memory (OOM) Errors
Problem: Application killed due to memory limit
Symptoms:
- Status: "OOMKilled"
- Pods restart frequently
- "JavaScript heap out of memory"
Solutions:
- Increase memory limit:
# manifest
resources:
memory_request: "1Gi"
memory_limit: "2Gi" # Increase from 512Mi
- Optimize application code:
// Bad: Loading entire dataset
const data = await db.collection.find().toArray();
// Good: Use streaming or pagination
const cursor = db.collection.find();
for await (const doc of cursor) {
process(doc);
}
- Increase Node.js heap size:
CMD ["node", "--max-old-space-size=1536", "server.js"]
- Enable autoscaling with memory threshold:
# Autoscaling config
memory_threshold: 70% # Scale before hitting limit
Service Connection Issues
Database Connection Failures
Problem: Cannot connect to database
Symptoms:
- "ECONNREFUSED"
- "Connection timeout"
- "Authentication failed"
Solutions:
- Verify service is connected (using correct STRONGLY_SERVICES structure):
const data = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const services = data.services || {};
// List all addon types
console.log('Addon types:', Object.keys(services.addons || {}));
// List all datasource types
console.log('Datasource types:', Object.keys(services.datasources || {}));
- Use correct access pattern:
// MongoDB addon
const mongoAddons = services.addons?.mongodb || [];
if (mongoAddons.length > 0) {
const mongo = mongoAddons[0];
const connectionString = mongo.connection?.connection_string;
console.log('MongoDB host:', mongo.connection?.host);
}
// PostgreSQL datasource
const pgSources = services.datasources?.postgres || [];
if (pgSources.length > 0) {
const pg = pgSources[0];
console.log('PG host:', pg.connection?.host);
console.log('PG auth:', pg.auth?.method);
}
- Test connection separately:
const { MongoClient } = require('mongodb');
async function testConnection() {
try {
const client = await MongoClient.connect(connectionString);
console.log('Connected to database');
await client.close();
} catch (err) {
console.error('Connection failed:', err.message);
}
}
- Check service health:
Navigate to Add-ons -> Click addon name -> Check status
Ensure addon is "Running"
AI Model API Errors
Problem: Cannot call AI model
Symptoms:
- "Unauthorized"
- "Model not found"
- Connection timeout
Solutions:
- Verify AI Gateway configuration:
const data = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const aiGateway = data.services?.aigateway;
console.log('AI Gateway base URL:', aiGateway?.base_url);
console.log('Available models:', aiGateway?.available_models?.length);
// List models
for (const model of aiGateway?.available_models || []) {
console.log(` - ${model.display_name} (${model.vendor_model_id})`);
console.log(` Type: ${model.type}, Model Type: ${model.model_type}`);
}
- Check API request format:
const model = aiGateway.available_models[0];
const response = await fetch(`${aiGateway.base_url}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Model-Id': model._id // Use the Strongly model ID
},
body: JSON.stringify({
model: model.vendor_model_id, // Use vendor model ID
messages: [{ role: 'user', content: 'Hello' }]
})
});
if (!response.ok) {
const error = await response.text();
console.error('API error:', error);
}
- Verify model is available (for self-hosted models):
Navigate to AI Gateway -> Models -> Check status
Ensure model is "Active"
Workflow Trigger Failures
Problem: Cannot invoke workflow
Symptoms:
- "Workflow not found"
- "Workflow execution failed"
- No response from workflow
Solutions:
- Verify workflow configuration:
const data = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
const workflows = data.services?.workflows?.available_workflows || [];
for (const wf of workflows) {
console.log(`Workflow: ${wf.name} (${wf.id})`);
console.log(` Trigger: ${wf.trigger_type}`);
console.log(` URL: ${wf.endpoints?.proxy_url}`);
console.log(` Method: ${wf.endpoints?.method}`);
}
- Check request format:
const workflow = workflows[0];
const response = await fetch(workflow.endpoints.proxy_url, {
method: workflow.endpoints.method || 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
// Match the workflow's input_schema
input: 'data'
})
});
const result = await response.json();
console.log('Workflow result:', result);
- Verify workflow is active:
Navigate to Workflows -> Check workflow status
Ensure workflow is "Active" and deployed
Performance Issues
High CPU Usage
Problem: CPU usage consistently high
Solutions:
- Profile your application:
// Node.js CPU profiling
node --prof server.js
node --prof-process isolate-*.log > profile.txt
- Optimize hot code paths:
// Bad: Synchronous operation in request handler
app.get('/users', (req, res) => {
const data = fs.readFileSync('users.json'); // Blocks event loop
res.json(JSON.parse(data));
});
// Good: Asynchronous operation
app.get('/users', async (req, res) => {
const data = await fs.promises.readFile('users.json');
res.json(JSON.parse(data));
});
- Add caching:
const cache = new Map();
app.get('/users', async (req, res) => {
if (cache.has('users')) {
return res.json(cache.get('users'));
}
const users = await db.users.find().toArray();
cache.set('users', users);
setTimeout(() => cache.delete('users'), 60000); // 1 min TTL
res.json(users);
});
- Scale horizontally:
# Enable autoscaling
cpu_threshold: 60% # Lower threshold
max_replicas: 10
Slow Response Times
Problem: API responses are slow
Solutions:
- Add database indexes:
-- Check slow queries
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- Add index
CREATE INDEX idx_users_email ON users(email);
- Implement connection pooling:
// Bad: New connection per request
app.get('/users', async (req, res) => {
const client = new MongoClient(url);
await client.connect();
const users = await client.db().collection('users').find().toArray();
await client.close();
res.json(users);
});
// Good: Connection pool
const pool = new MongoClient(url, { maxPoolSize: 10 });
await pool.connect();
app.get('/users', async (req, res) => {
const users = await pool.db().collection('users').find().toArray();
res.json(users);
});
- Add pagination:
app.get('/users', async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = 20;
const skip = (page - 1) * limit;
const users = await db.users
.find()
.skip(skip)
.limit(limit)
.toArray();
res.json({ users, page, hasMore: users.length === limit });
});
Deployment Issues
Cannot Redeploy
Problem: Redeploy doesn't work
Solutions:
- Check app status is not "Deploying"
- Wait for current operation to complete
- Try stopping and starting app first
- Contact support if stuck
Getting Help
Diagnostic Information
When contacting support, provide:
- App ID and Name
- Error logs from app details page
- Build logs if build failed
- Build status (pending, building, completed, failed, cancelled, timeout)
- Steps to reproduce the issue
- Screenshots of errors
- Manifest file content
Enable Debug Logging
# manifest
env:
- name: LOG_LEVEL
value: "debug" # Or "DEBUG" for Python
// Node.js
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info'
});
Common Log Patterns
Connection Refused:
Error: connect ECONNREFUSED 10.0.2.15:5432
-> Database not running or wrong host/port
Out of Memory:
<--- Last few GCs --->
FATAL ERROR: Reached heap limit
-> Increase memory limit or optimize code
Module Not Found:
Error: Cannot find module 'express'
-> Dependency not installed, check package.json
Port in Use:
Error: listen EADDRINUSE: address already in use :::3000
-> Port conflict, check manifest configuration
App Builder Unreachable:
Error: app-builder-unreachable - Cannot connect to app builder service
-> App builder backend is down or network issue