netbirdio/netbird · error
failed to presign URL
Error message
failed to presign URL
What it means
HTTP 500 from the S3-backed handler when presignClient.PresignPutObject fails. Presigning is local SigV4 signing, but the AWS SDK for Go v2 still needs resolvable credentials and a region (AWS_REGION is required at startup, BUCKET selects the S3 backend); the SDK error is logged server-side as 'Presign error'.
Source
Thrown at upload-server/server/s3.go:63
}
func (s *sThree) handlerGetUploadURL(w http.ResponseWriter, r *http.Request) {
if !isValidRequest(w, r) {
return
}
objectKey := getObjectKey(w, r)
if objectKey == "" {
return
}
req, err := s.presignClient.PresignPutObject(s.ctx, &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(objectKey),
}, s3.WithPresignExpires(15*time.Minute))
if err != nil {
http.Error(w, "failed to presign URL", http.StatusInternalServerError)
log.Errorf("Presign error: %v", err)
return
}
respondGetRequest(w, req.URL, objectKey)
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Give the server resolvable credentials: export AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY (plus AWS_SESSION_TOKEN for STS) or attach an IAM role
- Verify with 'aws sts get-caller-identity' run in the same environment as the server
- Confirm BUCKET and AWS_REGION are set for the process (missing AWS_REGION aborts startup earlier with a Fatal log)
- For IMDS timeouts, set AWS_EC2_METADATA_DISABLED=true together with explicit keys
Example fix
# before: no credentials reachable -> every GET /upload-url returns 500 docker run -e BUCKET=mybucket -e AWS_REGION=eu-west-1 nb/upload-server # after: credentials passed through export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... docker run -e BUCKET=mybucket -e AWS_REGION=eu-west-1 \ -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY nb/upload-server
Defensive patterns
Strategy: validation
Validate before calling
// smoke test at server startup: fail fast if presigning cannot work
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
if err != nil {
log.Fatalf("aws config: %v", err)
}
pc := s3.NewPresignClient(s3.NewFromConfig(cfg))
if _, err := pc.PresignPutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket), Key: aws.String("healthcheck"),
}, s3.WithPresignExpires(time.Minute)); err != nil {
log.Fatalf("presign unavailable: %v", err)
} Try / catch
A 500 'failed to presign URL' usually repeats until credentials are fixed: check the server log ('Presign error'), run aws sts get-caller-identity in the server environment, then retry the GET /upload-url. Prevention
- Validate credentials with aws sts get-caller-identity in the same env as the server
- Refresh STS tokens before expiry or use long-lived role credentials for long-running servers
- Alert on 'Presign error' log lines; they indicate credential drift, not client bugs
When it happens
Trigger: No credentials reachable by config.LoadDefaultConfig (no AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, no profile, no IAM role); EC2/ECS/K8s pod where IMDS or IRSA is unreachable so credential resolution fails at presign time; expired STS session tokens; malformed shared config file.
Common situations: Local development without 'aws configure'; Kubernetes pod missing the service-account role annotation or env; AssumeRole sessions expiring under a long-running server; credentials working yesterday but the token rotated.
Related errors
- management client is not initialised
- profile not found
- watcher closed unexpectedly
- failed to verify signature of artifact keys
- no keys found in bundle
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/2174fc3d9adedfcb.
Report an issue: GitHub.