linshenkx/prompt-optimizer · error · Error
S3 metadata lookup failed: ${s3ErrorMessage(error)}
Error message
S3 metadata lookup failed: ${s3ErrorMessage(error)} What it means
HeadObject-style metadata lookup in the S3-compatible store failed with a non-404 error; the raw error is wrapped with s3ErrorMessage for context. 404s are converted to null, so this is a genuine AWS error (auth, network, permissions, bucket).
Source
Thrown at packages/ui/src/utils/remote-backup.ts:1582
return Boolean(await this.head(path))
}
async head(path: string): Promise<RemoteObjectEntry | null> {
const normalized = normalizeObjectPath(path)
try {
const response = await this.client.send(new HeadObjectCommand({
Bucket: this.config.bucket,
Key: this.keyForPath(normalized),
}))
return {
path: normalized,
sizeBytes: typeof response.ContentLength === 'number' ? response.ContentLength : undefined,
updatedAt: response.LastModified instanceof Date ? response.LastModified.toISOString() : undefined,
contentType: typeof response.ContentType === 'string' ? response.ContentType : undefined,
}
} catch (error) {
if (isS3NotFoundError(error)) return null
throw new Error(`S3 metadata lookup failed: ${s3ErrorMessage(error)}`, { cause: error })
}
}
async put(
path: string,
body: Blob | ArrayBuffer | Uint8Array | string,
options?: { contentType?: string },
): Promise<RemoteObjectEntry> {
const normalized = normalizeObjectPath(path)
const blob = bodyToBlob(body, options?.contentType || JSON_MIME_TYPE)
const bytes = await bodyToUint8Array(blob)
const contentType = blob.type || options?.contentType || JSON_MIME_TYPE
try {
await this.client.send(new PutObjectCommand({
Bucket: this.config.bucket,
Key: this.keyForPath(normalized),
Body: bytes,
ContentType: contentType,View on GitHub (pinned to 3e677b1d9f)
Solutions
- Check the access key/secret and endpoint/bucket in the provider config
- Verify IAM policy allows s3:HeadObject on the bucket
- Test connectivity: aws s3api head-object --bucket ... --key ... with the same credentials
Defensive patterns
Strategy: try-catch
Type guard
const isS3AuthError = (e: unknown): boolean => /AccessDenied|InvalidAccessKeyId|SignatureDoesNotMatch/.test(String((e as Error)?.cause?.message ?? ''))
Try / catch
try { await store.stat(path) } catch (e) { if (isS3AuthError(e)) refreshCredentials(); else throw e } Prevention
- Rotate keys before expiry
- Test HeadObject during provider setup
When it happens
Trigger: stat(path) calling HeadObject with invalid credentials, wrong endpoint, non-existent bucket, network failure, or insufficient IAM permissions (s3:HeadObject).
Common situations: Expired/rotated access keys; wrong region/endpoint URL; IAM policy missing HeadObject; bucket deleted or renamed.
Related errors
- S3 download returned an unsupported response body
- S3 upload failed: ${s3ErrorMessage(error)}
- S3 list failed: ${s3ErrorMessage(error)}
- ${context}: ${response.status} ${message || response.statusT
- S3 object not found: ${normalized}
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/fa81d4e071243576.
Report an issue: GitHub.