Download Security and Size Limits
The Go-AI SDK includes built-in protection against memory exhaustion attacks when downloading files from URLs. This guide explains how download security works and how to customize size limits for your use case.
Overview
When generating content with images, videos, or audio from URLs, the SDK automatically enforces size limits to prevent:
- Memory exhaustion from downloading extremely large files
- Out-of-Memory (OOM) process crashes
- Resource depletion on your system
- Denial of Service (DoS) attacks
Default Protection
All downloads are automatically protected with a 2 GiB size limit.
This limit applies to:
- Image downloads for vision models
- Video downloads for video generation
- Audio downloads for transcription (future)
- Any user-provided URL passed to the SDK
// Automatically protected with 2 GiB limit
result, err := ai.GenerateImage(ctx, ai.GenerateImageOptions{
Model: model,
Prompt: "analyze this image",
Files: []provider.ImageFile{
{Type: "url", URL: "https://example.com/large-image.jpg"},
},
})
Why 2 GiB?
The 2 GiB default limit:
- Prevents most DoS attacks
- Allows legitimate large files (high-res images, long videos)
- Is easy to remember and reason about
- Matches the limit used by the TypeScript AI SDK
Custom Size Limits
For specific use cases, you can configure custom download limits:
Creating a Custom Download Function
import (
"github.com/digitallysavvy/go-ai/pkg/ai"
)
// Create single-URL download with 100 MB limit
customDownload := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 100 * 1024 * 1024, // 100 MB
})
Using Custom Downloads with Video Generation
result, err := ai.GenerateVideo(ctx, ai.GenerateVideoOptions{
Model: model,
Prompt: ai.VideoPrompt{
Text: "generate a video from this image",
Image: &ai.VideoPromptImage{
URL: "https://example.com/image.jpg",
},
},
DownloadWithMetadata: customDownload, // Use custom 100 MB limit
})
Additional Options
You can also set custom HTTP headers:
customDownload := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 500 * 1024 * 1024, // 500 MB
Headers: map[string]string{
"Authorization": "Bearer token",
"User-Agent": "MyApp/1.0",
},
})
How It Works
The download protection uses multiple layers:
1. Content-Length Check
Before downloading, the SDK checks the Content-Length HTTP header:
Content-Length: 3000000000 (3 GB)
Limit: 2147483648 (2 GiB)
→ Rejects immediately without downloading
2. Streaming with Size Tracking
Even if Content-Length is missing or incorrect, the SDK tracks bytes while streaming:
// Reads incrementally, not all at once
limitedReader := io.LimitReader(resp.Body, maxBytes+1)
data, err := io.ReadAll(limitedReader)
// Checks if limit was exceeded
if len(data) > maxBytes {
return DownloadError{...}
}
3. Context Cancellation
Downloads respect context cancellation for timeouts:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
download := ai.CreateURLDownload(opts)
data, err := download(ctx, url)
// Automatically cancelled after 30 seconds
Error Handling
When a download exceeds the size limit, you'll get a DownloadError:
result, err := ai.GenerateImage(ctx, opts)
if err != nil {
var downloadErr *providererrors.DownloadError
if errors.As(err, &downloadErr) {
// Download failed due to size limit or HTTP error
fmt.Printf("Download failed for %s: %v\n", downloadErr.URL, err)
if downloadErr.StatusCode > 0 {
fmt.Printf("HTTP %d: %s\n", downloadErr.StatusCode, downloadErr.StatusText)
}
}
}
Error Information
DownloadError provides:
URL: The URL that failedStatusCode: HTTP status code (if applicable)StatusText: HTTP status textMessage: Detailed error messageCause: Underlying error (if any)
Best Practices
1. Use Appropriate Limits for Your Use Case
// Small images for thumbnails
thumbnailDownload := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 10 * 1024 * 1024, // 10 MB
})
// High-resolution images for analysis
hiresDownload := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 500 * 1024 * 1024, // 500 MB
})
// Videos (use larger limit)
videoDownload := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 2 * 1024 * 1024 * 1024, // 2 GiB (default)
})
2. Validate URLs Before Downloading
func isAllowedDomain(rawURL string) bool {
parsed, err := url.Parse(rawURL)
if err != nil {
return false
}
allowedDomains := []string{"cdn.example.com", "storage.example.com"}
for _, domain := range allowedDomains {
if parsed.Host == domain {
return true
}
}
return false
}
if !isAllowedDomain(userProvidedURL) {
return errors.New("URL not from allowed domain")
}
3. Set Appropriate Timeouts
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
result, err := ai.GenerateVideo(ctx, ai.GenerateVideoOptions{
Model: model,
Prompt: prompt,
})
4. Handle Errors Gracefully
result, err := ai.GenerateImage(ctx, opts)
if err != nil {
var downloadErr *providererrors.DownloadError
if errors.As(err, &downloadErr) {
// Log error details
log.Printf("Download failed: %v", err)
// Return user-friendly error
return fmt.Errorf("failed to process image: file too large or unavailable")
}
return err
}
Security Considerations
Public-Facing Applications
If your application accepts URLs from untrusted users:
- ✅ Always use size limits (enabled by default)
- ✅ Validate URL domains (allowlist approach)
- ✅ Set timeout contexts (prevent slowloris attacks)
- ✅ Rate limit requests (prevent abuse)
- ✅ Monitor resource usage (detect anomalies)
Internal Applications
Even for internal services:
- ✅ Keep default limits (defense in depth)
- ✅ Validate URL schemes (prevent SSRF)
- ✅ Log download failures (detect issues early)
Low-Level API
pkg/internal/fileutil (the package underlying all of this) is a Go
internal/ package and cannot be imported outside this module. For advanced
use cases, build a download function with ai.CreateURLDownloadWithMetadata
or ai.CreateURLDownload instead, then call it directly:
import (
"github.com/digitallysavvy/go-ai/pkg/ai"
)
// Configure download options
download := ai.CreateURLDownloadWithMetadata(&ai.DownloadOptions{
MaxBytes: 50 * 1024 * 1024, // 50 MB
Headers: map[string]string{
"User-Agent": "MyApp/1.0",
},
})
// Download with options
result, err := download(ctx, url)
if err != nil {
var downloadErr *providererrors.DownloadError
if errors.As(err, &downloadErr) {
fmt.Printf("Download failed: %v\n", err)
}
return err
}
data := result.Data
FAQ
Q: Can I disable size limits?
A: No. Size limits cannot be disabled for security reasons. The maximum you can set is the platform's int64 limit, but this is strongly discouraged.
Q: What if I need to download files larger than 2 GiB?
A: Consider:
- Downloading the file separately with your own size checking
- Processing the file in chunks/streaming
- Using a different approach that doesn't require loading the entire file into memory
Q: Does this affect generated content from providers?
A: No. Limits only apply to downloads from user-provided URLs. Content generated by AI providers is handled separately.
Q: Will this break my existing code?
A: No. The 2 GiB default is very generous and unlikely to affect normal use cases. If you were downloading files larger than 2 GiB before, you should explicitly configure a larger limit.