cloudinary
semver
>=1.0.0 <3.0.0postconditions20functions17last verified2026-06-24coverage score85%Postconditions: what we check
- upload · upload-missing-error-handlingerrorWhennetwork error, validation error, authentication failure, or quota exceeded during uploadThrows
Plain object { message: string, http_code: number } — NOT a standard Error instance. HTTP 401: Authorization required (invalid/missing api_key, api_secret, or cloud_name). HTTP 403: Not allowed (unsigned upload attempt with restricted params). HTTP 400: Bad request (invalid file type, transformation params, or public_id format). HTTP 420: Rate limited (upload quota exceeded). HTTP 500: Internal server error. Node.js Error object: network-level failure (ECONNREFUSED, ETIMEDOUT, DNS failure).Required handlingMUST wrap cloudinary.v2.uploader.upload() in try-catch (for async/await) OR check error parameter in callback: (error, result) => { if (error) ... } IMPORTANT: error is a plain object {message, http_code}, not Error instance. Check error.http_code to distinguish auth (401), permission (403), rate-limit (420).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - upload_large · upload-large-missing-error-handlingerrorWhennetwork interruption, chunk upload failure, authentication failure, or file size exceededThrows
Plain object { message: string, http_code: number } on chunk failure. HTTP 400: File exceeds account upload limit (>100MB without plan support, or >100GB). HTTP 401: Authorization required (invalid credentials). HTTP 500: Internal server error during chunk assembly. Node.js Error object: network failure between chunks (ETIMEDOUT mid-upload). TimeoutError object ({ name: 'TimeoutError' }): request timeout during chunk POST.Required handlingMUST wrap cloudinary.v2.uploader.upload_large() in try-catch OR check error parameter in callback. Files >100MB require this method. Partial uploads are NOT automatically cleaned up on failure.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - upload_stream · upload-stream-missing-error-handlingerrorWhenstream read error, network interruption, memory issue, or authentication failureThrows
Error delivered via callback parameter, NOT as a rejected Promise. The callback is the ONLY way to receive errors from upload_stream(). Error structure: { message: string, http_code: number } (plain object, not Error instance). HTTP 401: Authorization required. HTTP 400: Invalid transformation parameters or file format rejected. Node.js Error: stream read failure or EPIPE on stream pipe.Required handlingMUST provide callback with error parameter: cloudinary.v2.uploader.upload_stream((error, result) => { if (error) ... }) Stream uploads REQUIRE callback-based error handling — there is no Promise to catch. Piping to the returned stream without a callback will silently swallow errors.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - destroy · destroy-missing-error-handlingerrorWhenauthentication failure, network error, permission denied, or unexpected server errorThrows
Plain object { message: string, http_code: number } for API errors. HTTP 401: Authorization required (invalid credentials). HTTP 403: Not allowed (insufficient permissions for this resource type or delivery type). HTTP 500: Internal server error. Node.js Error: network-level failure (ECONNREFUSED, ETIMEDOUT). IMPORTANT: Missing asset does NOT throw — resolves with { result: 'not found' }. Callers checking result.result === 'ok' will miss this silent no-op.Required handlingMUST wrap cloudinary.v2.uploader.destroy() in try-catch for auth/network errors. ALSO check result.result === 'ok' to detect missing assets (not thrown as error). Example: if (result.result !== 'ok') { log warning about missing asset }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - rename · rename-missing-error-handlingerrorWhensource asset not found (HTTP 404), target public_id already exists with overwrite:false (HTTP 409), authentication failure (HTTP 401), or permission denied (HTTP 403)Throws
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 404: Source asset not found (from_public_id does not exist). HTTP 409: Target public_id already exists and overwrite option is false (default). HTTP 401: Authorization required (invalid api_key/api_secret). HTTP 403: Not allowed (permission denied for this resource type). HTTP 400: Bad request (invalid public_id format).Required handlingMUST wrap cloudinary.v2.uploader.rename() in try-catch. Check error.http_code: 404 means source missing, 409 means target conflict. Pass overwrite: true explicitly if overwrite behavior is intended.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - rename · rename-silent-conflictwarningWhenrename target public_id already exists and overwrite option is not set to true (HTTP 409)Throws
Plain object { message: string, http_code: 409 } — rejected with conflict message.Required handlingCheck error.http_code === 409 to distinguish "target already exists" from other failures. Either use overwrite:true or handle the conflict explicitly.costlowin prodsilent failureusers seedegraded performancevisibilityvisibleSources[2] - explicit · explicit-missing-error-handlingerrorWhenasset not found (HTTP 404), invalid transformation parameters (HTTP 400), authentication failure (HTTP 401), or rate limit exceeded (HTTP 420)Throws
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 404: Asset not found (public_id does not exist yet or was deleted). HTTP 400: Invalid transformation parameters (bad crop mode, unsupported format). HTTP 401: Authorization required (invalid credentials). HTTP 420: Rate limited (too many transformation requests in short window). HTTP 500: Internal error (transformation pipeline failure for complex operations).Required handlingMUST wrap cloudinary.v2.uploader.explicit() in try-catch. Check error.http_code: 404 means asset not yet available (consider retry with backoff), 400 means transformation params are wrong (check transformation options).costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - add_tag · add-tag-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), invalid tag format (HTTP 400), or network failure — add_tag() silently returns empty list for non-existent public_idsThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 401: Authorization required. HTTP 403: Not allowed (permission denied). HTTP 400: Bad request (invalid tag format, too many public_ids). Node.js Error: network failure. SILENT: Non-existent public_ids do NOT throw — silently returns empty list.Required handlingMUST wrap cloudinary.v2.uploader.add_tag() in try-catch for auth/network errors. Check response.public_ids array to verify tags were actually applied.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - remove_tag · remove-tag-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), invalid tag or public_id format (HTTP 400), or network failure during tag removal operationThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 401: Authorization required. HTTP 403: Not allowed. HTTP 400: Invalid tag or public_id format.Required handlingMUST wrap cloudinary.v2.uploader.remove_tag() in try-catch. For access-control use cases, verify the operation succeeded via response.public_ids.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - api.delete_resources · delete-resources-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), Admin API rate limit exceeded (HTTP 420), or network failure during bulk asset deletionThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 401: Authorization required (invalid api_key/api_secret). HTTP 403: Not allowed (insufficient plan or resource-level permission). HTTP 420: Rate limited (Admin API hourly quota exceeded). HTTP 500: Internal server error. Node.js Error: network failure.Required handlingMUST wrap cloudinary.v2.api.delete_resources() in try-catch. Check error.http_code === 420 for rate limit and implement exponential backoff. Monitor X-FeatureRateLimit-Remaining header for proactive throttling. Check response.not_found[] array to verify which assets were actually deleted.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - api.resource · api-resource-missing-error-handlingerrorWhenasset not found (HTTP 404), authentication failure (HTTP 401), permission denied (HTTP 403), or Admin API rate limit exceeded (HTTP 420)Throws
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 404: Asset not found (public_id does not exist). HTTP 401: Authorization required. HTTP 403: Not allowed (insufficient permissions for this resource type). HTTP 420: Rate limited (Admin API quota exceeded).Required handlingMUST wrap cloudinary.v2.api.resource() in try-catch. Check error.http_code === 404 to handle missing assets gracefully (return null). Check error.http_code === 420 to implement backoff for high-volume metadata pipelines.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - update_metadata · update-metadata-missing-error-handlingerrorWhenauthentication failure (HTTP 401), invalid metadata field ID (HTTP 400), permission denied (HTTP 403), or network failureThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 400: Bad request (invalid metadata field external_id, value type mismatch, or pipe-encoded metadata string is malformed). HTTP 401: Authorization required (invalid api_key/api_secret). HTTP 403: Not allowed (insufficient permissions for metadata operations). Node.js Error: network failure (ECONNREFUSED, ETIMEDOUT).Required handlingMUST wrap cloudinary.v2.uploader.update_metadata() in try-catch. Check error.http_code === 400 to detect field ID mismatches (field was renamed/deleted). Note: partial success is NOT reported — if any field is invalid, the entire batch rejects. Validate metadata field external_ids against your Cloudinary dashboard before batch updates.costmediumin prodimmediate exceptionusers seelost datavisibilitysilentSources[2] - update_metadata · update-metadata-silent-partial-failurewarningWhennon-existent public_ids silently succeed — update_metadata does NOT throw 404 for missing assets but silently omits them from the resultThrows
Resolves (does NOT reject) when assets don't exist. Response: { public_ids: string[] } — only lists public_ids that were updated. Missing assets are silently omitted from response.public_ids.Required handlingAfter awaiting update_metadata(), compare response.public_ids against your input public_ids array. If any are missing, log a warning — those assets don't exist and their metadata was not updated. Example: const missing = input.filter(id => !result.public_ids.includes(id))costlowin prodsilent failureusers seelost datavisibilitysilentSources[2] - api.update · api-update-missing-error-handlingerrorWhenasset not found (HTTP 404), invalid metadata field or value (HTTP 400), authentication failure (HTTP 401), permission denied (HTTP 403), or Admin API rate limit exceeded (HTTP 420)Throws
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 404: Asset not found (public_id does not exist or was deleted). HTTP 400: Invalid metadata field external_id, tag format, or context syntax. HTTP 401: Authorization required (Admin API key + secret required). HTTP 403: Not allowed (insufficient plan or resource-type permission). HTTP 409: Conflict (trying to set access_mode to its current value). HTTP 420: Rate limited (Admin API hourly quota exceeded). Node.js Error: network failure (ECONNREFUSED, ETIMEDOUT).Required handlingMUST wrap cloudinary.v2.api.update() in try-catch. Check error.http_code === 404 to handle deleted assets gracefully. Check error.http_code === 420 to implement exponential backoff. Monitor X-FeatureRateLimit-Remaining in response for proactive throttling. Note: unlike delete_resources, api.update() updates a single asset atomically.costmediumin prodimmediate exceptionusers seelost datavisibilitysilentSources[4] - api.delete_resources_by_tag · delete-resources-by-tag-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), Admin API rate limit exceeded (HTTP 420), or network failure during bulk tag-based deletionThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 401: Authorization required (Admin API credentials required). HTTP 403: Not allowed (insufficient permissions for bulk delete). HTTP 420: Rate limited (Admin API quota exceeded — operation NOT applied). Node.js Error: network failure.Required handlingMUST wrap cloudinary.v2.api.delete_resources_by_tag() in try-catch. CRITICAL: Verify tag scope before calling — this deletes ALL assets with that tag. Use api.resources_by_tag() first to preview what will be deleted. Check error.http_code === 420 for rate limit and implement exponential backoff. Enable Cloudinary backup feature in account settings if data recovery is required. Consider using delete_resources() with explicit public_ids for safer targeted deletion.costhighin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - api.delete_resources_by_tag · delete-resources-by-tag-catastrophic-misuseerrorWhenbulk tag-based deletion applied without prior scope verification — resolves successfully but deletes more assets than intended due to shared or generic tag nameThrows
Resolves (does NOT reject) when the deletion succeeds — even if it deleted more assets than intended. Response: { deleted: {}, deleted_counts: {}, partial: boolean, rate_limit_... } No per-asset confirmation — only aggregate counts.Required handlingALWAYS call api.resources_by_tag(tag) first to preview the asset count and verify the tag scope before deletion. Use a dedicated deletion-scoped tag (e.g., "to-delete-YYYY-MM-DD") to avoid accidental scope bleed. Store the list of deleted public_ids from resources_by_tag() before calling delete_resources_by_tag() for audit logging.costcriticalin prodsilent failureusers seelost datavisibilitysilentSources[4] - search.execute · search-execute-missing-error-handlingerrorWheninvalid search expression (HTTP 400), missing Admin API credentials (HTTP 401), rate limit exceeded (HTTP 420), or network failureThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 400: Bad request (invalid search expression syntax, malformed Lucene query). HTTP 401: Authorization required (Admin API credentials required, not just upload key). HTTP 420: Rate limited (Admin API quota, search counts against the same limit). HTTP 500: Internal error (query too broad, index timeout).Required handlingMUST wrap cloudinary.v2.search.expression(...).execute() in try-catch. Check error.http_code === 400 to detect expression syntax errors. Check error.http_code === 401 — search requires Admin API credentials (api_key + api_secret), not just cloud_name. Client-side usage will always return 401. Implement pagination with next_cursor for large result sets to avoid timeouts.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5] - remove_all_tags · remove-all-tags-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), invalid public_id format (HTTP 400), or network failure during bulk tag-clearing operationThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 401: Authorization required (invalid api_key/api_secret). HTTP 403: Not allowed (permission denied). HTTP 400: Bad request (invalid public_id format, too many public_ids). HTTP 500: Internal server error. Node.js Error: network failure (ECONNREFUSED, ETIMEDOUT). SILENT: Non-existent public_ids do NOT throw — silently returns empty list.Required handlingMUST wrap cloudinary.v2.uploader.remove_all_tags() in try-catch for auth/network errors. For access-control rollback, compare response.public_ids against your input array to verify the tag-clearing was actually applied to every asset. Missing public_ids in the response indicate assets that no longer exist — their access-control state cannot be guaranteed by this call.costlowin prodimmediate exceptionusers seedegraded performancevisibilitysilentSources[2] - create_archive · create-archive-missing-error-handlingerrorWhenauthentication failure (HTTP 401), invalid archive parameters (HTTP 400), permission denied (HTTP 403), rate limit exceeded (HTTP 420), or network failure during server-side archive assemblyThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 400: Bad request (invalid target_format, too many source assets, or conflicting selector params). HTTP 401: Authorization required (invalid api_key/api_secret). HTTP 403: Not allowed (archive generation not enabled on plan). HTTP 420: Rate limited (Upload API archive quota exceeded). HTTP 500: Internal error (archive assembly failure for large sets). Node.js Error: network failure (ECONNREFUSED, ETIMEDOUT mid-assembly).Required handlingMUST wrap cloudinary.v2.uploader.create_archive() (and create_zip()) in try-catch. Check error.http_code === 400 to detect bad archive params (try a smaller selector or different target_format). Check error.http_code === 420 for rate-limit and implement exponential backoff before retry. For customer-facing download flows, present a user-friendly fallback rather than the raw error.message. Note: create_zip() delegates to create_archive() with target_format="zip" — the same error envelope applies.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - api.create_folder · create-folder-missing-error-handlingerrorWhenauthentication failure (HTTP 401), permission denied (HTTP 403), folder already exists (HTTP 409 Conflict), invalid folder path (HTTP 400), Admin API rate limit exceeded (HTTP 420), or network failure during folder creationThrows
Plain object { message: string, http_code: number } — NOT a standard Error. HTTP 400: Bad request (invalid folder path — leading slash, illegal chars). HTTP 401: Authorization required (Admin API credentials required). HTTP 403: Not allowed (insufficient permissions for folder ops). HTTP 409: Already exists (folder is already present at this path). HTTP 420: Rate limited (Admin API hourly quota exceeded — folder ops count against the same limit). HTTP 500: Internal server error. Node.js Error: network failure (ECONNREFUSED, ETIMEDOUT).Required handlingMUST wrap cloudinary.v2.api.create_folder() in try-catch. Check error.http_code === 409 to detect idempotent re-creation — treat as a no-op success in tenant onboarding flows (the folder is already there). Check error.http_code === 420 for rate limit and implement exponential backoff. Validate folder path format (no leading slash, no illegal characters) before calling to avoid HTTP 400.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4]
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Official documentation
- [1]cloudinary.com/documentation/upload_imagesUpload Images
- [2]cloudinary.com/documentation/image_upload_api_referenceImage Upload Api Reference
- [3]support.cloudinary.com/hc/en-us/community360026620212 Stream Upload Catching Errors NODE JS
- [4]cloudinary.com/documentation/admin_apiAdmin Api
- [5]cloudinary.com/documentation/search_apiSearch Api
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources for cloudinary Nark profile
Package: cloudinary
Contract Version: 1.0.0
Last Updated: 2026-02-25
Official Documentation
- Node.js SDK Integration: https://cloudinary.com/documentation/node_integration
- Upload API Reference: https://cloudinary.com/documentation/image_upload_api_reference
- Node.js Image/Video Upload: https://cloudinary.com/documentation/node_image_and_video_upload
Community Resources
- Stream Upload Error Handling: https://support.cloudinary.com/hc/en-us/community/posts/360026620212-stream-upload-catching-errors-NODE-JS-
- GitHub Repository: https://github.com/cloudinary/cloudinary_npm
Security Advisories
CVE-2025-12613 - Arbitrary Argument Injection
- Severity: High (CVSS 8.8)
- Affected: cloudinary < 2.7.0
- Source: https://security.snyk.io/vuln/SNYK-JS-CLOUDINARY-10495740
Error Scenarios
- Network errors: Connection timeouts, interruptions
- Validation errors: Invalid file format, files >100MB without upload_large()
- Authentication errors: Invalid API credentials
- Resource errors: Asset not found (destroy)
Real-World Patterns
Async/Await with Try-Catch (70% of usage)
try {
const result = await cloudinary.v2.uploader.upload(file);
} catch (error) {
console.error('Upload failed:', error);
}
Callback-Based (30% of usage)
cloudinary.v2.uploader.upload(file, (error, result) => {
if (error) console.error(error);
});
Testing Methodology
- proper-error-handling.ts: Correct patterns → 0 violations expected
- missing-error-handling.ts: Incorrect patterns → 4 violations expected
- instance-usage.ts: Instance detection tests
Version Compatibility
- Tested: cloudinary ^1.0.0, ^2.0.0
- Minimum Required: 2.7.0 (CVE-2025-12613 fix)
- API: v2 (cloudinary.v2.uploader) recommended
Reviewed By: Claude Sonnet 4.5
Review Date: 2026-02-25
Need a different package?
Request a profile