immich-app/immich · critical · Error
Failed to decode redis options
Error message
Failed to decode redis options
What it means
When REDIS_URL starts with ioredis://, Immich treats the remainder as base64-encoded JSON ioredis options and tries to JSON.parse(Buffer.from(...).toString()). Any decode/parse failure is rethrown as Error('Failed to decode redis options', { cause }). Standard redis:// URLs are not affected — only the ioredis:// base64 scheme.
Source
Thrown at server/src/repositories/config.repository.ts:216
geodata: join(buildFolder, 'geodata'),
web: join(buildFolder, 'www'),
};
let redisConfig = {
host: dto.REDIS_HOSTNAME || 'redis',
port: dto.REDIS_PORT || 6379,
db: dto.REDIS_DBINDEX || 0,
username: dto.REDIS_USERNAME || undefined,
password: dto.REDIS_PASSWORD || undefined,
path: dto.REDIS_SOCKET || undefined,
};
const redisUrl = dto.REDIS_URL;
if (redisUrl && redisUrl.startsWith('ioredis://')) {
try {
redisConfig = JSON.parse(Buffer.from(redisUrl.slice(10), 'base64').toString());
} catch (error) {
throw new Error('Failed to decode redis options', { cause: error });
}
}
const includedTelemetries =
dto.IMMICH_TELEMETRY_INCLUDE === 'all'
? new Set(Object.values(ImmichTelemetry))
: asSet<ImmichTelemetry>(dto.IMMICH_TELEMETRY_INCLUDE, []);
const excludedTelemetries = asSet<ImmichTelemetry>(dto.IMMICH_TELEMETRY_EXCLUDE, []);
const telemetries = setDifference(includedTelemetries, excludedTelemetries);
for (const telemetry of telemetries) {
if (!TELEMETRY_TYPES.has(telemetry)) {
throw new Error(`Invalid telemetry found: ${telemetry}`);
}
}
const databaseConnection: DatabaseConnectionParams = dto.DB_URL
? { connectionType: 'url', url: dto.DB_URL }View on GitHub (pinned to 199723261c)
Solutions
- Inspect the cause to see whether it was a base64 decode error or a JSON syntax error.
- Regenerate the payload with Buffer.from(JSON.stringify(opts)).toString('base64') and prefix with ioredis://.
- Prefer a plain redis://[:password@]host:port[/db] URL unless you need advanced ioredis options.
Defensive patterns
Strategy: validation
Validate before calling
const url = process.env.REDIS_URL ?? '';
if (url.startsWith('ioredis://')) {
const json = Buffer.from(url.slice('ioredis://'.length), 'base64').toString('utf8');
JSON.parse(json); // throws early with a clear cause if malformed
} Type guard
const isIoredisScheme = (u: string): boolean => u.startsWith('ioredis://'); Try / catch
try {
startServer();
} catch (e) {
if ((e as Error).message === 'Failed to decode redis options') {
console.error((e as Error).cause);
// switch to redis:// URL or fix base64 payload
} else throw e;
} Prevention
- Prefer a plain redis:// URL unless advanced ioredis options are required.
- Generate base64 payloads programmatically, not by hand.
- Unit-test the encode/decode round-trip in your deploy tooling.
When it happens
Trigger: Setting REDIS_URL=ioredis://<payload> where <payload> is not valid base64, or decodes to invalid JSON, or does not match the expected ioredis options shape.
Common situations: Generating the base64 payload incorrectly; trailing newline/whitespace in the encoded string; confusing this scheme with a normal redis://host:port URL; payload was encoded from a different ioredis version option keys.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid environment variables: \n - [${path}] ${issue.messa
- Invalid worker(s) found: ${workers.join(',')}
- Invalid telemetry found: ${telemetry}
- Failed to read helmet file: ${helmetFile}
- Unable to determine worker type
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/869a18eb23e7e619.
Report an issue: GitHub.