{"record":{"id":"4081f4a02561f2e9","repo":"hcengineering/platform","slug":"duplicated-storage-name-config-name-skipping-c","errorCode":null,"errorMessage":"Duplicated storage name ${config.name}, skipping config:${st}","messagePattern":"Duplicated storage name (.+?), skipping config:(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"foundations/server/packages/server-storage/src/starter.ts","lineNumber":73,"sourceCode":"      // No protocol, add empty one\n      url = 'empty://' + url\n      hasProtocol = false\n    }\n    const uri = new URL(url)\n    const config: StorageConfig = {\n      kind,\n      name,\n      endpoint: (hasProtocol ? uri.protocol + '//' : '') + uri.hostname, // Port should go away\n      port: uri.port !== '' ? parseInt(uri.port) : undefined\n    }\n\n    // Add all extra parameters\n    uri.searchParams.forEach((v, k) => {\n      ;(config as any)[k] = v\n    })\n\n    if (storageConfig.storages.find((it) => it.name === config.name) !== undefined) {\n      throw new Error(`Duplicated storage name ${config.name}, skipping config:${st}`)\n    }\n    storageConfig.storages.push(config)\n    storageConfig.default = config.name\n  }\n}\n\nexport function createStorageFromConfig (config: StorageConfig): StorageAdapter {\n  let adapter: StorageAdapter\n  const kind = config.kind\n  if (kind === MINIO_CONFIG_KIND) {\n    const c = config as MinioConfig\n    if (c.endpoint == null || c.accessKey == null || c.secretKey == null) {\n      throw new Error('One of endpoint/accessKey/secretKey values are not specified')\n    }\n    adapter = new MinioService(c)\n  } else if (kind === S3_CONFIG_KIND) {\n    const c = config as S3Config\n    if (c.endpoint == null || c.accessKey == null || c.secretKey == null) {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/server/packages/server-storage/src/starter.ts#L55-L91","documentation":"While parsing STORAGE_CONFIG, each entry's name defaults to its kind, and entries are pushed into storageConfig.storages which must have unique names. If an entry's computed name already exists, parseStorageEnv throws Error('Duplicated storage name <name>, skipping config:<st>'). Duplicate symbolic names would make the fallback/target lookup ambiguous, so it's treated as a hard config error.","triggerScenarios":"Two ';'-separated STORAGE_CONFIG entries resolving to the same name — e.g. 'minio|minio:9000...;minio|other:9000...' (both default to name 'minio'), or an explicit name repeated like 'minio,primary|...;s3,primary|...'.","commonSituations":"Copy-pasting a storage entry to add a second bucket/endpoint but forgetting to change the explicit ,name part; same kind listed twice assuming names would auto-suffix; templating loops generating configs where the name variable didn't change per iteration.","solutions":["Give each storage entry a unique explicit name: 'kind,uniquename|uri|contentTypes'","If two entries of the same kind are intentional (e.g. minio + s3 fallback), rename one so the name component differs","Search STORAGE_CONFIG for duplicated tokens before the '|' and fix the repeat","Restart and confirm the server lists the expected number of storages"],"exampleFix":"// before\nSTORAGE_CONFIG=minio,primary|a:9000...;s3,primary|b...\n// after\nSTORAGE_CONFIG=minio,primary|a:9000...;s3,backup|b...","handlingStrategy":"validation","validationCode":"const names = (process.env.STORAGE_CONFIG ?? '').split(';').map(s => s.split('|')[0].split(',')[1] ?? s.split('|')[0].split(',')[0])\nconst dupes = names.filter((n, i) => names.indexOf(n) !== i)\nif (dupes.length > 0) throw new Error(`Duplicate storage names: ${dupes.join(',')}`)","typeGuard":"function hasUniqueNames (entries: string[]): boolean {\n  const names = entries.map(e => { const [kindName] = e.split('|'); const [kind, name] = kindName.split(','); return name ?? kind })\n  return new Set(names).size === names.length\n}","tryCatchPattern":"try {\n  parseStorageEnv(storageEnv, storageConfig)\n} catch (err) {\n  if ((err as Error).message.startsWith('Duplicated storage name')) {\n    console.error('Fix STORAGE_CONFIG: ', (err as Error).message)\n    process.exit(1)\n  }\n  throw err\n}","preventionTips":["Always give multi-storage setups explicit unique names (kind,myname|...)","Template generated configs with per-entry unique name variables","Add a config preflight check comparing entry names","Document naming conventions per environment"],"tags":["configuration","storage","duplicate","parsing"],"backgroundTag":"invalid-storage-config","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}