immich-app/immich · error · Error
Invalid storage template
Error message
Invalid storage template
What it means
StorageTemplateService validates a candidate storage template by rendering it against a sample asset. If rendering throws (unknown token, bad token syntax, malformed template), the catch rethrows a plain Error 'Invalid storage template' with the original error as cause (storage-template.service.ts:128). This blocks the template from being saved.
Source
Thrown at server/src/services/storage-template.service.ts:128
this.render(compiled, {
asset: {
fileCreatedAt: new Date(),
originalPath: '/upload/test/IMG_123.jpg',
type: AssetType.Image,
id: 'd587e44b-f8c0-4832-9ba3-43268bbf5d4e',
} as StorageAsset,
filename: 'IMG_123',
extension: 'jpg',
albumName: 'album',
albumStartDate: new Date(),
albumEndDate: new Date(),
make: 'FUJIFILM',
model: 'X-T50',
lensModel: 'XF27mm F2.8 R WR',
});
} catch (error) {
this.logger.warn(`Storage template validation failed: ${JSON.stringify(error)}`);
throw new Error('Invalid storage template', { cause: error });
}
}
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
return { ...storageTokens, presetOptions: storagePresets };
}
@OnEvent({ name: 'AssetMetadataExtracted' })
async onAssetMetadataExtracted({ source, assetId }: ArgOf<'AssetMetadataExtracted'>) {
await this.jobRepository.queue({ name: JobName.StorageTemplateMigrationSingle, data: { source, id: assetId } });
}
@OnJob({ name: JobName.StorageTemplateMigrationSingle, queue: QueueName.StorageTemplateMigration })
async handleMigrationSingle({ id }: JobOf<JobName.StorageTemplateMigrationSingle>): Promise<JobStatus> {
const config = await this.getConfig({ withCache: true });
const isStorageTemplateEnabled = config.storageTemplate.enabled;
if (!isStorageTemplateEnabled) {
return JobStatus.Skipped;View on GitHub (pinned to 199723261c)
Solutions
- Build the template only from tokens listed by getStorageTemplateOptions() (exposed via the config options endpoint).
- Start from a known preset and modify incrementally, validating each change.
- After an upgrade, review release notes for renamed/removed storage tokens and update custom templates.
Example fix
// before
{ storageTemplate: { template: '{{albumName}}/{{foo}}/{{fullname}}' } }
// after
{ storageTemplate: { template: '{{y}}/{{MM}}/{{fullname}}' } } Defensive patterns
Strategy: validation
Validate before calling
const options = await systemConfigApi.getStorageTemplateOptions(); // tokens + presets
const allowedTokens = new Set(Object.keys(options.storageTokens ?? {}));
const usedTokens = extractTokens(newConfig.storageTemplate.template); // e.g. ['y','MM','fullname']
if (usedTokens.some((t) => !allowedTokens.has(t))) {
throw new Error('Storage template contains an unknown token.');
}
await systemConfigApi.update(newConfig); Type guard
const isKnownToken = (token: string, allowed: Set<string>): token is string => allowed.has(token);
Try / catch
try {
await systemConfigApi.update(newConfig);
} catch (e) {
if (/Invalid storage template/i.test(String((e as Error).message))) {
showTemplateEditorWithError((e as Error).cause);
} else throw e;
} Prevention
- Build templates from tokens returned by the config options endpoint.
- Modify presets incrementally and validate each change.
- Re-check token names after Immich upgrades.
When it happens
Trigger: Saving system config (PUT /system-config) with a storageTemplate.template value containing an unrecognized token like {{foo}} or malformed handlebars/bracket syntax that the renderer cannot parse.
Common situations: Hand-editing the template with a token not in storageTokens, version upgrades that renamed/removed tokens, or copy-pasting a template from an incompatible Immich version.
Related errors
- Invalid SMTP configuration
- Unknown CLIP model: ${newConfig.machineLearning.clip.modelNa
- Logging cannot be changed while the environment variable IMM
- Cannot update configuration while IMMICH_CONFIG_FILE is in u
- {error.message}
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/3fc3e839050a2778.
Report an issue: GitHub.