Overview
Image generation operations in AI Studio are asynchronous. Each image goes through multiple status states from initial creation to completion. This guide explains the status lifecycle and how to track processing progress.
Status Values
The imageGeneration table includes a status field with the following possible values:
Initial state after image upload. The image is queued for processing but hasn’t started yet.
The image is currently being processed by the AI model. This typically takes 10-30 seconds.
Processing finished successfully. The resultImageUrl field contains the processed image URL.
Processing encountered an error. The errorMessage field contains details about what went wrong.
Status Lifecycle
Normal Flow
pending - Image created, waiting for processing to start
processing - AI model is enhancing the image
completed - Result is ready and stored
Error Flow
pending - Image created, waiting for processing
processing - AI processing started
failed - An error occurred (with error message)
Image Generation Schema
interface ImageGeneration {
id : string ;
workspaceId : string ;
userId : string ;
projectId : string ;
// Image URLs
originalImageUrl : string ; // Source image (always present)
resultImageUrl : string | null ; // Processed image (null until completed)
// AI parameters
prompt : string ; // Style transformation prompt
// Version tracking
version : number ; // 1, 2, 3... for edit history
parentId : string | null ; // Links to root image for versioning
// Status tracking
status : "pending" | "processing" | "completed" | "failed" ;
errorMessage : string | null ; // Error details if status is failed
// Additional info
metadata : {
editedFrom ?: string ; // Previous version ID
editedAt ?: string ; // ISO timestamp
editMode ?: "remove" | "add" ; // For inpaint operations
model ?: string ; // AI model used
} | null ;
createdAt : Date ;
updatedAt : Date ;
}
Checking Status
Using Database Queries
Query the image generation record directly:
import { getImageGenerationById } from '@/lib/db/queries' ;
const image = await getImageGenerationById ( imageId );
console . log ( 'Status:' , image . status );
if ( image . status === 'completed' ) {
console . log ( 'Result URL:' , image . resultImageUrl );
}
if ( image . status === 'failed' ) {
console . error ( 'Error:' , image . errorMessage );
}
Polling Pattern
For real-time status updates, implement a polling pattern:
async function waitForCompletion ( imageId : string , maxAttempts = 60 ) {
for ( let i = 0 ; i < maxAttempts ; i ++ ) {
const image = await getImageGenerationById ( imageId );
if ( image . status === 'completed' ) {
return { success: true , resultUrl: image . resultImageUrl };
}
if ( image . status === 'failed' ) {
return { success: false , error: image . errorMessage };
}
// Wait 2 seconds before next check
await new Promise ( resolve => setTimeout ( resolve , 2000 ));
}
throw new Error ( 'Timeout waiting for image processing' );
}
Real-Time Progress Tracking
When processing via Trigger.dev background jobs, you can track detailed progress:
interface ProcessImageStatus {
step : "fetching" | "uploading" | "processing" | "saving" | "completed" | "failed" ;
label : string ;
progress ?: number ;
}
interface InpaintImageStatus {
step : "fetching" | "preparing" | "processing" | "saving" | "completed" | "failed" ;
label : string ;
progress ?: number ;
}
Progress Steps
Process Image Flow
Fetching
Loading image record from database Progress : 10%
Uploading
Preparing image for AI processing (uploading to Fal.ai storage) Progress : 25%
Processing
AI model is enhancing the image Progress : 50%
Saving
Downloading and storing result in Supabase Progress : 80%
Completed
Processing finished successfully Progress : 100%
Inpaint Image Flow
Fetching
Loading source image record Progress : 10%
Preparing
Processing and resizing mask to match image dimensions Progress : 25%
Processing
AI inpainting in progress (removing or adding objects) Progress : 50%
Saving
Creating new version and storing result Progress : 80%
Completed
Edit completed successfully Progress : 100%
Project Status Aggregation
Projects maintain aggregate status based on their images:
interface Project {
id : string ;
name : string ;
status : "pending" | "processing" | "completed" | "failed" ;
imageCount : number ; // Total images in project
completedCount : number ; // Successfully processed images
}
Status Rules
pending All images are in pending state (not started).
processing At least one image is processing, or some completed but not all.
completed All images have status completed (imageCount === completedCount).
failed All images are either failed or completed, with at least one failed.
Error Messages
When status is failed, the errorMessage field contains details:
Common Error Messages
The image record doesn’t exist in the database. Resolution : Verify the imageId is correct.
The original image URL is not accessible. Resolution : Check that the image was uploaded successfully to Supabase storage.
The AI model didn’t return a result. Resolution : This may be due to content safety filters or invalid input. Check the prompt and image content.
Couldn’t retrieve the processed image from Fal.ai. Resolution : This is usually temporary. Retry the processing.
Generic error during AI processing. Resolution : Check logs for more details. May be due to API rate limits or service issues.
Inpaint-Specific Errors
The maskDataUrl parameter is missing. Resolution : Provide a valid base64-encoded mask image.
The mask data URL is malformed. Resolution : Ensure mask follows format: data:image/png;base64,{base64data}
Unable to read source image dimensions for mask resizing. Resolution : Ensure source image is a valid image file.
Status Updates
Status transitions are handled automatically:
Database Updates
// Start processing
await updateImageGeneration ( imageId , {
status: 'processing'
});
// Mark as completed
await updateImageGeneration ( imageId , {
status: 'completed' ,
resultImageUrl: storedResultUrl ,
errorMessage: null
});
// Mark as failed
await updateImageGeneration ( imageId , {
status: 'failed' ,
errorMessage: error . message
});
Project Count Updates
After status changes, project counts are recalculated:
await updateProjectCounts ( projectId );
// Counts completed images and updates project status
Monitoring Best Practices
Poll efficiently : Check status every 2-3 seconds with a maximum timeout of 2 minutes.
Handle timeouts : If polling exceeds timeout, treat as a system error and allow retry.
Log failures : Always log the full error message for debugging failed images.
Show progress : Use the Trigger.dev metadata progress values (10%, 25%, 50%, 80%, 100%) for user feedback.
Example: Status Monitoring UI
function ImageStatusBadge ({ status } : { status : string }) {
const statusConfig = {
pending: { color: 'gray' , label: 'Queued' , icon: 'clock' },
processing: { color: 'blue' , label: 'Processing...' , icon: 'spinner' },
completed: { color: 'green' , label: 'Ready' , icon: 'check' },
failed: { color: 'red' , label: 'Failed' , icon: 'xmark' }
};
const config = statusConfig [ status ];
return (
< Badge color = {config. color } >
< Icon name = {config. icon } />
{ config . label }
</ Badge >
);
}