Troubleshooting Common Issues
This guide helps you diagnose and fix common issues when deploying and running applications on the Strongly platform.
Build Failures
Slow Builds
Problem: A build takes a long time. Builds have no time limit: the build keeps running until it succeeds or fails, or until you cancel it.
Symptoms:
- Build stays in
buildingfor a long time - 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)
Cannot connect to app builder service
Problem: The platform could not take the deploy
Symptoms:
- Error:
Cannot connect to app builder service - Deployment fails before the build starts
Solutions:
- Retry deployment: Wait a moment and deploy again
- Contact your administrator if it keeps happening
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:
# The manifest (and your Dockerfile, if you ship one) must be in the 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
- Builds stuck for more than twice the timeout are automatically marked failed; you can also trigger this cleanup via the REST API (
POST /builds/cleanup/stale) - 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"
- The app keeps restarting
- The status bar's reason mentions "CrashLoopBackOff"
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:
- Listen on the port your manifest declares: the platform routes to that port, and sets the
PORTenvironment variable to it, so bindingPORTor the declared port both work. "Port already in use" means something else in the container already holds that port.
// server.js
const PORT = process.env.PORT || 3000;
app.listen(PORT);
# manifest - the port the app listens on (PORT is set to it)
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:
- The status bar's reason mentions "OOMKilled"
- The app restarts frequently
- "JavaScript heap out of memory"
Solutions:
-
Give the app more memory: on its Overview tab, Edit the Size card (or pick a larger environment) and restart the app. The app runs at exactly the size you set.
-
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 (deployment autoscaling config, thresholds are integer percentages):
# Autoscaling config
memory_threshold: 70 # Scale before hitting limit (default: 80)
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.modelType}`);
}
- 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 (thresholds are integer percentages)
cpu_threshold: 60 # Lower threshold (default: 70)
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)
- 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: Cannot connect to app builder service
-> The platform could not take the deploy; retry, then contact your administrator