{"record":{"id":"3fc3e839050a2778","repo":"immich-app/immich","slug":"invalid-storage-template","errorCode":null,"errorMessage":"Invalid storage template","messagePattern":"Invalid storage template","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/storage-template.service.ts","lineNumber":128,"sourceCode":"      this.render(compiled, {\n        asset: {\n          fileCreatedAt: new Date(),\n          originalPath: '/upload/test/IMG_123.jpg',\n          type: AssetType.Image,\n          id: 'd587e44b-f8c0-4832-9ba3-43268bbf5d4e',\n        } as StorageAsset,\n        filename: 'IMG_123',\n        extension: 'jpg',\n        albumName: 'album',\n        albumStartDate: new Date(),\n        albumEndDate: new Date(),\n        make: 'FUJIFILM',\n        model: 'X-T50',\n        lensModel: 'XF27mm F2.8 R WR',\n      });\n    } catch (error) {\n      this.logger.warn(`Storage template validation failed: ${JSON.stringify(error)}`);\n      throw new Error('Invalid storage template', { cause: error });\n    }\n  }\n\n  getStorageTemplateOptions(): ConfigTemplateStorageOptionDto {\n    return { ...storageTokens, presetOptions: storagePresets };\n  }\n\n  @OnEvent({ name: 'AssetMetadataExtracted' })\n  async onAssetMetadataExtracted({ source, assetId }: ArgOf<'AssetMetadataExtracted'>) {\n    await this.jobRepository.queue({ name: JobName.StorageTemplateMigrationSingle, data: { source, id: assetId } });\n  }\n\n  @OnJob({ name: JobName.StorageTemplateMigrationSingle, queue: QueueName.StorageTemplateMigration })\n  async handleMigrationSingle({ id }: JobOf<JobName.StorageTemplateMigrationSingle>): Promise<JobStatus> {\n    const config = await this.getConfig({ withCache: true });\n    const isStorageTemplateEnabled = config.storageTemplate.enabled;\n    if (!isStorageTemplateEnabled) {\n      return JobStatus.Skipped;","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/storage-template.service.ts#L110-L146","documentation":"During config validation, StorageTemplateService renders the configured storage template against a sample asset (FUJIFILM X-T50 sample metadata); if the template string or rendering fails, it wraps the cause in 'Invalid storage template', rejecting the config save.","triggerScenarios":"Saving a storage template containing unknown tokens, malformed template syntax, illegal characters/paths (e.g. leading '/', '..'), or expressions that fail to render with sample EXIF data.","commonSituations":"Hand-editing the template with typos like {{Y}} instead of {{y}}; using removed/unsupported variables; templates that produce empty paths or duplicate-segment mistakes; copy-pasted templates from older Immich versions.","solutions":["Pick a preset from the storage template options or reset to the default template: {{y}}/{{MM}}/{{dd}}/{{filename}}.","Validate each token against the documented list ({{y}}, {{MM}}, {{filename}}, {{album}}, etc.) and fix typos.","Remove illegal path constructs (absolute paths, '..', reserved characters) from the template.","Check the logged 'Storage template validation failed' warning for the underlying cause and fix accordingly."],"exampleFix":"// before\nstorageTemplate: { template: '{{YYYY}}-{{MM}}/{{originalFileName}}' }\n// after\nstorageTemplate: { template: '{{y}}/{{MM}}/{{filename}}' }","handlingStrategy":"try-catch","validationCode":"// render the template against sample data before saving\nimport { renderTemplate } from 'src/utils/storage-template';\nawait renderTemplate({ template, asset: sampleAsset, album: null }); // throws if invalid","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateConfig(config);\n} catch (e) {\n  if (/Invalid storage template/.test(e.message)) {\n    // reset to a known-good preset and re-open the editor\n    config.storageTemplate.template = '{{y}}/{{MM}}/{{filename}}';\n  } else throw e;\n}","preventionTips":["Use only documented storage tokens ({{y}}, {{MM}}, {{filename}}, ...)","Test templates in the settings UI preview before saving","Avoid absolute paths and '..' segments in templates","Re-validate templates copied from older Immich versions"],"tags":["immich","storage-template","config-validation"],"backgroundTag":"invalid-config-value","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}