About
supabase-error-translator-js maps Supabase error codes to user-facing messages in
multiple languages. It is useful when your app receives technical error codes from
Supabase Auth, Storage, Realtime, or PostgREST and needs a localized message for the UI.
The package does not call Supabase and does not depend on @supabase/supabase-js. It is a
small translation registry plus a few helper functions.
This project is maintained independently. It is not officially associated with, endorsed by, or affiliated with Supabase.
Supported Languages
| Language | Code |
|---|---|
| English | en |
| Arabic | ar |
| German | de |
| Spanish | es |
| French | fr |
| Japanese | ja |
| Korean | ko |
| Polish | pl |
| Portuguese | pt |
| Chinese | zh |
Supported Services
| Service | Status |
|---|---|
auth | Translated error codes are available. |
storage | Translated error codes are available. |
realtime | Translated error codes are available. |
database | PostgreSQL and PostgREST error codes are available. |
functions | The service is accepted by the API, but translations are currently empty. Unknown fallback text is returned. |
What The Package Returns
The package returns strings, not rich error objects. It intentionally keeps the public API simple so callers can use the result in React, Next.js, Node.js, or any browser-bundled application.
Installation
Requirements
supabase-error-translator-js requires Node.js 18 or newer when used in a Node.js
environment. Browser apps can consume it through their normal bundler.
Package Manager
Install from npm:
npm install supabase-error-translator-js
With pnpm:
pnpm add supabase-error-translator-js
With yarn:
yarn add supabase-error-translator-js
Import
import { translateErrorCode } from 'supabase-error-translator-js';
The package ships JavaScript and TypeScript declaration files from dist/.
Quick Start
Translate a Supabase Auth error code:
import { translateErrorCode } from 'supabase-error-translator-js';
const message = translateErrorCode('invalid_credentials', 'auth', 'de');
console.log(message);
Check for exact translations without fallback messages:
import { lookupErrorCode } from 'supabase-error-translator-js';
const result = lookupErrorCode('invalid_credentials', 'auth', 'de');
console.log(result.message);
Import a single immutable language map:
import de from 'supabase-error-translator-js/translations/de';
console.log(de.services.auth.invalid_credentials);
Set a process-wide or browser-session default language:
import { setLanguage, translateErrorCode } from 'supabase-error-translator-js';
setLanguage('es');
const message = translateErrorCode('email_not_confirmed', 'auth');
Use browser language detection:
import { setLanguage } from 'supabase-error-translator-js';
setLanguage('auto');
For server-side rendering or request handlers, prefer passing the language to
translateErrorCode() for each call:
import { translateErrorCode, type SupportedLanguage } from 'supabase-error-translator-js';
export function translateSupabaseError(code: string | undefined, userLanguage: SupportedLanguage) {
return translateErrorCode(code, 'auth', userLanguage);
}
Language Handling
Supported Codes
The package uses ISO 639-1 language codes:
import { getSupportedLanguages } from 'supabase-error-translator-js';
console.log(getSupportedLanguages());
// ['en', 'ar', 'de', 'es', 'fr', 'ja', 'ko', 'pl', 'pt', 'zh']
Default Language
The default language is English:
import { getCurrentLanguage } from 'supabase-error-translator-js';
console.log(getCurrentLanguage());
// 'en'
Call setLanguage() to change the default:
import { setLanguage } from 'supabase-error-translator-js';
setLanguage('fr');
Unsupported values fall back to English.
Browser Detection
Pass auto to use the primary browser language from navigator.language:
import { setLanguage } from 'supabase-error-translator-js';
setLanguage('auto');
For example, de-DE resolves to de. Unsupported browser languages fall back to en.
When navigator is unavailable, detection also falls back to en.
Per-Call Language Override
The third argument to translateErrorCode() overrides the current default without
mutating it:
import { getCurrentLanguage, translateErrorCode } from 'supabase-error-translator-js';
const message = translateErrorCode('phone_exists', 'auth', 'pt');
console.log(getCurrentLanguage());
// Still whatever was previously set.
This is the safer pattern for multi-user server code because setLanguage() stores
module-level state.
Services And Fallbacks
Supabase can reuse the same error code string in different services. Because of that,
translateErrorCode() requires a service argument.
import { translateErrorCode } from 'supabase-error-translator-js';
translateErrorCode('TenantNotFound', 'storage', 'en');
translateErrorCode('TenantNotFound', 'realtime', 'en');
Services
| Service | Typical source |
|---|---|
auth | supabase.auth.* calls |
storage | supabase.storage.* calls |
realtime | Realtime channel and connection status errors |
database | PostgreSQL SQLSTATE and PostgREST PGRST error codes |
functions | Reserved for Supabase Edge Functions. Translation maps are currently empty. |
Fallback Chain
Empty, whitespace-only, or missing codes are normalized to unknown_error.
For other codes, the lookup order is:
- Target language, selected service, selected code
- English, selected service, selected code
- Target language
unknown_error - English
unknown_error
Unsupported service names are handled defensively at runtime and return the localized unknown-error fallback.
Strict Lookup
lookupErrorCode() is intentionally different from translateErrorCode(): it performs
only an exact lookup and returns message: undefined when no exact translation exists.
import { lookupErrorCode } from 'supabase-error-translator-js';
const result = lookupErrorCode('not_a_real_code', 'auth', 'de');
console.log(result.message);
// undefined
Empty, whitespace-only, or missing codes also return message: undefined.
unknown_error is returned only when that code is passed explicitly.
Unknown Codes
import { translateErrorCode } from 'supabase-error-translator-js';
const message = translateErrorCode('not_a_real_code', 'auth', 'de');
This returns the German unknown-error message if it exists, otherwise the English unknown-error message.
API Reference
setLanguage(lang)
function setLanguage(lang: SupportedLanguage | 'auto'): void;
Sets the module-level default language.
| Argument | Description |
|---|---|
lang | A supported language code or auto. Unsupported values fall back to en at runtime. |
Use per-call language overrides instead of setLanguage() in request-scoped server code.
translateErrorCode(code, service, lang?)
function translateErrorCode(
code: string | undefined,
service: ErrorService,
lang?: SupportedLanguage | 'auto',
): string;
Returns a translated string for a Supabase error code.
| Argument | Description |
|---|---|
code | The Supabase error code. Empty, whitespace-only, or undefined values are treated as unknown_error. |
service | One of auth, storage, realtime, database, or functions. |
lang | Optional per-call language override. auto uses browser detection. |
lookupErrorCode(code, service, lang?)
function lookupErrorCode(
code: string | undefined,
service: ErrorService,
lang?: SupportedLanguage | 'auto',
): ErrorCodeLookupResult;
Performs an exact lookup without fallback messages.
| Argument | Description |
|---|---|
code | The Supabase error code. Empty, whitespace-only, or undefined values return undefined. |
service | One of auth, storage, realtime, database, or functions. |
lang | Optional per-call language override. Unsupported values resolve to en. |
The result contains the normalized code, resolved language, service, and either the exact
message or undefined:
type ErrorCodeLookupResult = {
code: string;
service: ErrorService;
language: SupportedLanguage;
message: string | undefined;
};
lookupErrorCode() does not fall back to English and does not fall back to
unknown_error. Passing unknown_error explicitly returns the localized unknown-error
message.
getCurrentLanguage()
function getCurrentLanguage(): SupportedLanguage;
Returns the current module-level default language.
getSupportedLanguages()
function getSupportedLanguages(): SupportedLanguage[];
Returns a copy of the supported language-code list.
isSupportedLanguage(lang)
function isSupportedLanguage(lang: string): lang is SupportedLanguage;
Runtime guard for supported language codes.
isSupportedService(service)
function isSupportedService(service: string): service is ErrorService;
Runtime guard for supported service names.
Constants And Types
import {
SUPPORTED_LANGUAGES,
SUPPORTED_SERVICES,
type ErrorCodeLookupResult,
type ErrorService,
type SupportedLanguage,
type TranslationStructure,
} from 'supabase-error-translator-js';
Translation Subpaths
import { translations } from 'supabase-error-translator-js/translations';
import de from 'supabase-error-translator-js/translations/de';
import en from 'supabase-error-translator-js/translations/en';
Supported language subpaths:
supabase-error-translator-js/translations/ar
supabase-error-translator-js/translations/de
supabase-error-translator-js/translations/en
supabase-error-translator-js/translations/es
supabase-error-translator-js/translations/fr
supabase-error-translator-js/translations/ja
supabase-error-translator-js/translations/ko
supabase-error-translator-js/translations/pl
supabase-error-translator-js/translations/pt
supabase-error-translator-js/translations/zh
Translation maps are immutable at runtime. The functions service is reserved and
currently has empty maps.
Examples
Supabase Auth
import { useState, type FormEvent } from 'react';
import { translateErrorCode, type SupportedLanguage } from 'supabase-error-translator-js';
import { supabase } from './supabaseClient';
type Props = {
language: SupportedLanguage;
};
export function SignInForm({ language }: Props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errorMessage, setErrorMessage] = useState<string | null>(null);
async function signIn(event: FormEvent) {
event.preventDefault();
setErrorMessage(null);
const { error } = await supabase.auth.signInWithPassword({ email, password });
if (error) {
setErrorMessage(translateErrorCode(error.code, 'auth', language));
}
}
return (
<form onSubmit={signIn}>
{errorMessage && <p role="alert">{errorMessage}</p>}
<input value={email} onChange={(event) => setEmail(event.target.value)} />
<input
type="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
<button type="submit">Sign in</button>
</form>
);
}
Database And PostgREST
Database errors often expose SQLSTATE codes such as 23505 or PostgREST codes such as
PGRST204.
import { translateErrorCode } from 'supabase-error-translator-js';
import { supabase } from './supabaseClient';
const { error } = await supabase.from('profiles').insert({
username: 'existing-user',
});
if (error) {
const message = translateErrorCode(error.code, 'database', 'en');
console.log(message);
}
Storage
import { translateErrorCode } from 'supabase-error-translator-js';
import { supabase } from './supabaseClient';
async function uploadAvatar(file: File) {
const { error } = await supabase.storage.from('avatars').upload('public/avatar.png', file);
if (error) {
const message = translateErrorCode(error.code, 'storage', 'es');
console.log(message);
}
}
Realtime
Realtime status callbacks do not always include a structured error. Use
unknown_error when no code is present.
import { translateErrorCode } from 'supabase-error-translator-js';
import { supabase } from './supabaseClient';
const channel = supabase.channel('room').subscribe((status, error) => {
if (status === 'CHANNEL_ERROR') {
const message = translateErrorCode(error?.code, 'realtime', 'fr');
console.log(message);
}
});
Runtime Guards
import {
isSupportedLanguage,
isSupportedService,
translateErrorCode,
} from 'supabase-error-translator-js';
const language = isSupportedLanguage(userLanguage) ? userLanguage : 'en';
const service = isSupportedService(serviceFromLog) ? serviceFromLog : 'auth';
const message = translateErrorCode(codeFromLog, service, language);
Strict Lookup
Use lookupErrorCode() when application logic needs to distinguish exact translations
from fallback messages.
import { lookupErrorCode } from 'supabase-error-translator-js';
const result = lookupErrorCode('invalid_credentials', 'auth', 'de');
if (result.message) {
console.log(result.message);
} else {
console.log('No exact translation is available for this code.');
}
Per-Language Translation Data
Subpath imports expose immutable static maps for each supported language.
import { translations } from 'supabase-error-translator-js/translations';
import de from 'supabase-error-translator-js/translations/de';
console.log(de.services.auth.invalid_credentials);
console.log(translations.en.services.storage.NoSuchBucket);
Migration Guide
Explicit Public Exports
The package now declares an explicit public exports map. Documented top-level imports
continue to work:
import { lookupErrorCode, translateErrorCode } from 'supabase-error-translator-js';
New public translation subpaths are available:
import { translations } from 'supabase-error-translator-js/translations';
import de from 'supabase-error-translator-js/translations/de';
Undocumented deep imports, such as importing files from dist/ directly through the
package name, are not supported by the public API and may be blocked by the exports map.
Use the top-level package import or the documented translations subpaths instead.
From v2 To v3
Version 3 uses ISO 639-1 language codes for Japanese, Korean, and Chinese.
| Before | After |
|---|---|
jp | ja |
kr | ko |
cn | zh |
Update calls like this:
import { setLanguage } from 'supabase-error-translator-js';
setLanguage('ja');
setLanguage('ko');
setLanguage('zh');
translateErrorCode() without a lang argument now uses the language set by
setLanguage() instead of always trying browser detection.
From v1 To v2
Version 2 added service-specific translation maps. translateErrorCode() now requires a
service argument.
import { translateErrorCode } from 'supabase-error-translator-js';
// v1
translateErrorCode('invalid_credentials');
// v2 and newer
translateErrorCode('invalid_credentials', 'auth');
Choose the service from the Supabase API that produced the error.
Contributing
See the repository contribution guide for the full workflow.
Local Setup
pnpm install
Checks
pnpm run lint
pnpm run type-check
pnpm test
pnpm run build
pnpm run prettier:check
Translation Changes
When adding or changing translations:
- Keep every language map structurally aligned with English.
- Add or update tests when the public behavior changes.
- Keep
unknown_errordefined for every language. - Document new public behavior in this manual.
The test suite checks that every supported language defines the same service keys as the English translation map.
Documentation
Build the mdBook locally:
mdbook build docs
Serve it locally while editing:
mdbook serve docs
Changelog
All notable changes to this project will be documented in this file.
[3.2.0] - 2026-07-06 Changes
Features
- Add per-language translation subpath imports under
supabase-error-translator-js/translations/{lang}. - Add
lookupErrorCode()for strict exact-message lookups without fallback messages. - Add an explicit package
exportsmap for the supported public import surface.
Improvements
- Freeze exported translation maps at runtime, including direct per-language subpath imports.
- Keep
functionsreserved with intentionally empty service maps.
Compatibility
- The top-level
translateErrorCode()API and fallback behavior are unchanged. - Undocumented deep imports are not part of the supported API and may be blocked by the package exports map.
[3.1.0] - 2026-05-28 Changes
Features
- Arabic translations (#22, @ahmedalmnsour): Add
aracross Auth, Realtime, Storage, and Database. - Language and service guards (#21, @srothgan): Export supported-language and supported-service helpers.
Improvements
- Translation registry (#21, @srothgan): Derive supported languages from one registry.
- Fallback handling (#21, @srothgan): Validate service names at runtime and expand fallback coverage.
Documentation
- mdBook manual (#23, @srothgan): Add the
docs/manual and GitHub Pages workflow. - Focused README (#23, @srothgan): Move extended usage, API, examples, and migration material into docs.
- Contributor workflow (@srothgan): Clarify the external-contributor workflow.
CI and Dependencies
- Audit cleanup (#11, @srothgan): Resolve 24 advisories and add Node/pnpm project foundations.
- Tooling refresh (#12, @srothgan): Upgrade to ESLint 10, TypeScript 6, rimraf 6, and Vitest.
- CI matrices (#13, @srothgan): Refresh Actions and test/build on Node 20, 22, and 24.
- Release automation (#14, #20, @srothgan): Add trusted npm publishing, GitHub Releases, Knip, and audit gates.
- Repository polish (#19, @srothgan): Add issue/PR templates, CodeQL, and README workflow badges.
Compatibility
- Additive release (#21, #22, #23): Keep existing language codes, service keys, and fallback behavior compatible.
[3.0.1] - 2025-08-30 Changes
Fixes
- Build cleanup: Clean
distbefore compiling so stalecn,jp, andkrbundles are removed after the ISO-code migration. - API stability: No API changes.
[3.0.0] - 2025-08-29 Changes
Breaking Changes
- ISO language codes: Replace legacy language codes with ISO 639-1 codes:
jp->jafor Japanese.kr->kofor Korean.cn->zhfor Chinese.
Fixes
- Default language handling: Make
translateErrorCode()without alangargument usecurrentLanguage.
Documentation
- Migration guidance: Update examples and API references for the new language codes.
Migration Guide
Update language-code usage:
// Before v3.0.0
setLanguage('jp');
setLanguage('kr');
setLanguage('cn');
// v3.0.0 and newer
setLanguage('ja');
setLanguage('ko');
setLanguage('zh');
[2.2.1] - 2025-06-01 Changes
Documentation
- Contributor guide (#8): Rename and refresh the contribution guide.
Fixes
- Translation polish (#8): Clean up wording across language helpers and translation maps.
[2.2.0] - 2025-05-27 Changes
Features
- Expanded language support: Add Japanese, Korean, Polish, Portuguese, and Chinese translations.
- Global coverage: Bring supported languages to 9.
Documentation
- Language examples: Update the README language table, auto-detection examples, and API notes.
[2.1.0] - 2025-05-09 Changes
Features
- Database errors: Add PostgreSQL SQLSTATE and PostgREST error-code translations.
- Constraint guidance: Add user-friendly messages for common database constraints and query failures.
[2.0.1] - 2025-05-04 Changes
Fixes
- npm package build: Fix the npm build issue in the 2.0 release line.
[2.0.0] - 2025-05-04 Changes
Breaking Changes
- Service-scoped translations: Organize translations by Supabase service.
- API signature: Require a service argument in
translateErrorCode().
// Before v2.0.0
translateErrorCode(code, lang);
// v2.0.0 and newer
translateErrorCode(code, service, lang);
Features
- Storage errors: Add Supabase Storage error-code translations.
- Overlapping error codes: Resolve same-code cases by service context, such as
TenantNotFoundin Storage versus Realtime. - Type safety: Add stronger service and translation-structure types.
[1.1.1] - 2025-05-03 Changes
Documentation
- README cleanup: Apply small README fixes.
[1.1.0] - 2025-05-03 Changes
Features
- Usage examples: Expand README examples.
- Project docs: Add Code of Conduct and contribution guidance.
Fixes
- Unknown-code handling: Improve
unknown_errorfallback behavior. - Empty input handling: Handle undefined and empty error codes.
[1.0.1] - 2025-05-01 Changes
Initial Release
- Auth translations: Add initial English, German, French, and Spanish authentication translations.