> ## Documentation Index
> Fetch the complete documentation index at: https://support.lilt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rename the Object Storage Bucket

<Note>
  From release **N+2** (the first release that ships the ENG-32953 migration) stored object
  references no longer carry a scheme or bucket, and renaming the bucket or switching between
  MinIO, S3 and GCS is a configuration change only, provided every service is configured with
  the same bucket. This procedure applies to releases up to **N+1**, and to a JSON or text
  column that still embeds a URI.
</Note>

## Overview

LILT stores object references in the database as full URIs that include the bucket name, for example `s3://lilt/prod/converter-service/...`. Every service that reads one of these URIs checks that the bucket segment equals the bucket it is configured with, and refuses the read if it does not. Copying the objects into a bucket with a different name and pointing the configuration at it is therefore not enough: every reference written before the move still names the old bucket and fails outright.

The symptoms are immediate and affect only pre-existing work. New uploads and new exports succeed, while anything created before the rename fails with `File export failed`, a `500` or `Local URI` error on download, a TMX re-import failure, or `Wrong bucket name` from the neural services. Because the errors show a plausible-looking S3 path, the wrong bucket segment is easy to miss.

This article covers rewriting the stored URIs so an existing installation can move to a bucket with a new name. It applies after the objects have been copied key-for-key, for example by following [Migrate Object Storage (MinIO to S3)](/self-managed/v6.1/migrate-object-storage-minio-to-s3). If you can keep the bucket name identical across the move, do so and skip this procedure entirely.

The table and column inventory below was verified against LILT 5.3.4. Other releases may add columns; the census in the first step is the check.

## Order of Operations

1. Back up the application database (`lilt_dev` by default), or at minimum the tables listed below.
2. Quiesce writers. Scale `front`, `converter-core`, `file-translation-core`, `tm-core`, `job-core`, and `file-job-core` to zero, or pick a quiet window. In-flight RabbitMQ messages carry full URIs, so let the queues drain (`rabbitmqctl list_queues`) before rewriting.
3. Run the census. Every prefix group should show the old bucket or `NULL`. Record the counts.
4. Run the rewrite inside one transaction. Each `UPDATE` is preceded by a `COUNT`; after the update the same count must be zero.
5. Run the JSON and text column rewrites only for columns whose census count was greater than zero. On a stock 5.3.x installation every one of those is expected to be zero.
6. Update the bucket name in every configuration location listed at the end, redeploy, and re-run the census. Only the new bucket should remain.

Set the two values once per session so the statements below can be pasted as written. Both end with a slash so that `lilt` cannot match `lilt-prod`.

```sql theme={null}
SET @old = 's3://lilt/';
SET @new = 's3://lilt-prod/';
```

The `LIKE CONCAT(@old, '%')` anchor cannot match a URI that already carries the new bucket, so re-running any statement is harmless.

## Census

Read-only. Group every URI column by its `scheme://bucket` prefix.

#### Permanent references

These are read for source download, re-export, TMX re-import, estimates, and PDF re-export. Every row must be rewritten.

```sql theme={null}
SELECT 'Documents.fileLocation' col, SUBSTRING_INDEX(fileLocation,'/',3) p, COUNT(*) FROM Documents WHERE fileLocation IS NOT NULL AND fileLocation<>'' GROUP BY p;
SELECT 'Documents.xliffLocation', SUBSTRING_INDEX(xliffLocation,'/',3), COUNT(*) FROM Documents WHERE xliffLocation IS NOT NULL AND xliffLocation<>'' GROUP BY 2;
SELECT 'Files.fileLocation', SUBSTRING_INDEX(fileLocation,'/',3), COUNT(*) FROM Files WHERE fileLocation IS NOT NULL AND fileLocation<>'' GROUP BY 2;
SELECT 'FileTranslations.xliffLocation', SUBSTRING_INDEX(xliffLocation,'/',3), COUNT(*) FROM FileTranslations WHERE xliffLocation IS NOT NULL AND xliffLocation<>'' GROUP BY 2;
SELECT 'FileTranslations.exportUri', SUBSTRING_INDEX(exportUri,'/',3), COUNT(*) FROM FileTranslations WHERE exportUri IS NOT NULL AND exportUri<>'' GROUP BY 2;
SELECT 'UserResources.fileLocation', SUBSTRING_INDEX(fileLocation,'/',3), COUNT(*) FROM UserResources WHERE fileLocation IS NOT NULL AND fileLocation<>'' GROUP BY 2;
SELECT 'UserResources.xliff (URI rows)', SUBSTRING_INDEX(xliff,'/',3), COUNT(*) FROM UserResources WHERE xliff LIKE 's3:%' OR xliff LIKE 'gs:%' GROUP BY 2;
SELECT 'Estimates.fileLocation', SUBSTRING_INDEX(fileLocation,'/',3), COUNT(*) FROM Estimates WHERE fileLocation IS NOT NULL AND fileLocation<>'' GROUP BY 2;
SELECT 'DocumentIntermediateFiles.storageLocation', SUBSTRING_INDEX(storageLocation,'/',3), COUNT(*) FROM DocumentIntermediateFiles WHERE storageLocation IS NOT NULL AND storageLocation<>'' GROUP BY 2;
```

`UserResources.xliff` is named like a content column but holds the imported-XLIFF URI for translation memory and termbase resources.

#### Regenerable references

The application can regenerate these, but it reads the stored value first (the Download button, hard-delete cleanup), so rewrite them too.

```sql theme={null}
SELECT 'Documents.exportURI', SUBSTRING_INDEX(exportURI,'/',3), COUNT(*) FROM Documents WHERE exportURI IS NOT NULL AND exportURI<>'' GROUP BY 2;
SELECT 'Projects.exportURI', SUBSTRING_INDEX(exportURI,'/',3), COUNT(*) FROM Projects WHERE exportURI IS NOT NULL AND exportURI<>'' GROUP BY 2;
SELECT 'Memories.exportURI', SUBSTRING_INDEX(exportURI,'/',3), COUNT(*) FROM Memories WHERE exportURI IS NOT NULL AND exportURI<>'' GROUP BY 2;
SELECT 'Jobs.exportURI', SUBSTRING_INDEX(exportURI,'/',3), COUNT(*) FROM Jobs WHERE exportURI IS NOT NULL AND exportURI<>'' GROUP BY 2;
SELECT 'Uploads.fileLocation', SUBSTRING_INDEX(fileLocation,'/',3), COUNT(*) FROM Uploads WHERE fileLocation IS NOT NULL AND fileLocation<>'' GROUP BY 2;
SELECT 'DocumentExports.storageLocation', SUBSTRING_INDEX(storageLocation,'/',3), COUNT(*) FROM DocumentExports WHERE storageLocation<>'' GROUP BY 2;
SELECT 'JobExports.storageLocation', SUBSTRING_INDEX(storageLocation,'/',3), COUNT(*) FROM JobExports WHERE storageLocation<>'' GROUP BY 2;
SELECT 'ProjectExports.storageLocation', SUBSTRING_INDEX(storageLocation,'/',3), COUNT(*) FROM ProjectExports WHERE storageLocation<>'' GROUP BY 2;
SELECT 'MemoryExports.storageLocation', SUBSTRING_INDEX(storageLocation,'/',3), COUNT(*) FROM MemoryExports WHERE storageLocation<>'' GROUP BY 2;
```

#### Legacy single-slash form

Older releases wrote `s3:/bucket/...` with one slash, and core still accepts it. Expect zero.

```sql theme={null}
SELECT 'legacy Documents.fileLocation', COUNT(*) FROM Documents WHERE fileLocation LIKE REPLACE(CONCAT(@old,'%'),'://',':/')
UNION ALL SELECT 'legacy Documents.xliffLocation', COUNT(*) FROM Documents WHERE xliffLocation LIKE REPLACE(CONCAT(@old,'%'),'://',':/')
UNION ALL SELECT 'legacy Files.fileLocation', COUNT(*) FROM Files WHERE fileLocation LIKE REPLACE(CONCAT(@old,'%'),'://',':/');
```

#### JSON and text columns

These columns could embed a URI. No 5.3.4 writer puts one there, so expect zero everywhere. Rewrite only what the census finds.

```sql theme={null}
SELECT 'AsyncRequests.requestMessage', COUNT(*) FROM AsyncRequests WHERE CAST(requestMessage AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'ScheduledEvents.payLoad', COUNT(*) FROM ScheduledEvents WHERE CAST(payLoad AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'FileJobs.jobParams', COUNT(*) FROM FileJobs WHERE CAST(jobParams AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'UserNotifications.data', COUNT(*) FROM UserNotifications WHERE CAST(data AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'ExternalModels.providerConfig', COUNT(*) FROM ExternalModels WHERE CAST(providerConfig AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'Projects.metadata', COUNT(*) FROM Projects WHERE CAST(metadata AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'Documents.converterConfig', COUNT(*) FROM Documents WHERE converterConfig LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'Projects.converterConfig', COUNT(*) FROM Projects WHERE converterConfig LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'FileTranslations.converterConfig', COUNT(*) FROM FileTranslations WHERE CAST(converterConfig AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'ConverterConfigs.config', COUNT(*) FROM ConverterConfigs WHERE CAST(config AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'Documents.apiMeta', COUNT(*) FROM Documents WHERE apiMeta LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'ConnectorJobs.args', COUNT(*) FROM ConnectorJobs WHERE CAST(args AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'Connectors.args', COUNT(*) FROM Connectors WHERE CAST(args AS CHAR) LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'NeuralBatchTranslationRequests.request (in-flight only)', COUNT(*) FROM NeuralBatchTranslationRequests WHERE request LIKE CONCAT('%',@old,'%')
UNION ALL SELECT 'NeuralBatchRequests.request (legacy rows only)', COUNT(*) FROM NeuralBatchRequests WHERE CAST(request AS CHAR) LIKE CONCAT('%',@old,'%');
```

If the neural services run with `storageType: minio` (the stock 5.3.x value), their internal URIs use the `minio://` scheme instead of `s3://`. Repeat the two neural counts with `@old` set to the `minio://` form.

## Rewrite

Run as one transaction. `Documents.fileLocation` goes first because front derives new export URIs from it. Compare each count before and after; after must be zero.

```sql theme={null}
START TRANSACTION;

SELECT COUNT(*) FROM Documents WHERE fileLocation LIKE CONCAT(@old,'%');
UPDATE Documents SET fileLocation = REPLACE(fileLocation,@old,@new) WHERE fileLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Documents WHERE xliffLocation LIKE CONCAT(@old,'%');
UPDATE Documents SET xliffLocation = REPLACE(xliffLocation,@old,@new) WHERE xliffLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Documents WHERE exportURI LIKE CONCAT(@old,'%');
UPDATE Documents SET exportURI = REPLACE(exportURI,@old,@new) WHERE exportURI LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Files WHERE fileLocation LIKE CONCAT(@old,'%');
UPDATE Files SET fileLocation = REPLACE(fileLocation,@old,@new) WHERE fileLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM FileTranslations WHERE xliffLocation LIKE CONCAT(@old,'%');
UPDATE FileTranslations SET xliffLocation = REPLACE(xliffLocation,@old,@new) WHERE xliffLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM FileTranslations WHERE exportUri LIKE CONCAT(@old,'%');
UPDATE FileTranslations SET exportUri = REPLACE(exportUri,@old,@new) WHERE exportUri LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM UserResources WHERE fileLocation LIKE CONCAT(@old,'%');
UPDATE UserResources SET fileLocation = REPLACE(fileLocation,@old,@new) WHERE fileLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM UserResources WHERE xliff LIKE CONCAT(@old,'%');
UPDATE UserResources SET xliff = REPLACE(xliff,@old,@new) WHERE xliff LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Estimates WHERE fileLocation LIKE CONCAT(@old,'%');
UPDATE Estimates SET fileLocation = REPLACE(fileLocation,@old,@new) WHERE fileLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM DocumentIntermediateFiles WHERE storageLocation LIKE CONCAT(@old,'%');
UPDATE DocumentIntermediateFiles SET storageLocation = REPLACE(storageLocation,@old,@new) WHERE storageLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Projects WHERE exportURI LIKE CONCAT(@old,'%');
UPDATE Projects SET exportURI = REPLACE(exportURI,@old,@new) WHERE exportURI LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Memories WHERE exportURI LIKE CONCAT(@old,'%');
UPDATE Memories SET exportURI = REPLACE(exportURI,@old,@new) WHERE exportURI LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Jobs WHERE exportURI LIKE CONCAT(@old,'%');
UPDATE Jobs SET exportURI = REPLACE(exportURI,@old,@new) WHERE exportURI LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM Uploads WHERE fileLocation LIKE CONCAT(@old,'%');
UPDATE Uploads SET fileLocation = REPLACE(fileLocation,@old,@new) WHERE fileLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM DocumentExports WHERE storageLocation LIKE CONCAT(@old,'%');
UPDATE DocumentExports SET storageLocation = REPLACE(storageLocation,@old,@new) WHERE storageLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM JobExports WHERE storageLocation LIKE CONCAT(@old,'%');
UPDATE JobExports SET storageLocation = REPLACE(storageLocation,@old,@new) WHERE storageLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM ProjectExports WHERE storageLocation LIKE CONCAT(@old,'%');
UPDATE ProjectExports SET storageLocation = REPLACE(storageLocation,@old,@new) WHERE storageLocation LIKE CONCAT(@old,'%');
SELECT COUNT(*) FROM MemoryExports WHERE storageLocation LIKE CONCAT(@old,'%');
UPDATE MemoryExports SET storageLocation = REPLACE(storageLocation,@old,@new) WHERE storageLocation LIKE CONCAT(@old,'%');

COMMIT;
```

If the census found legacy single-slash rows, normalise them to the double-slash form of the new bucket in the same transaction:

```sql theme={null}
SET @old1 = REPLACE(@old,'://',':/');
UPDATE Documents SET fileLocation  = REPLACE(fileLocation, @old1,@new) WHERE fileLocation  LIKE CONCAT(@old1,'%');
UPDATE Documents SET xliffLocation = REPLACE(xliffLocation,@old1,@new) WHERE xliffLocation LIKE CONCAT(@old1,'%');
UPDATE Files     SET fileLocation  = REPLACE(fileLocation, @old1,@new) WHERE fileLocation  LIKE CONCAT(@old1,'%');
```

#### JSON and text columns

Run a statement only if its census count was greater than zero. Check the column type first with `SHOW CREATE TABLE`: a JSON-typed column needs the `CAST(... AS JSON)` form so MySQL re-validates the document, while a TEXT column takes plain `REPLACE`. The replacement string contains no quotes or backslashes, so the JSON stays valid.

```sql theme={null}
-- TEXT column
UPDATE AsyncRequests SET requestMessage = REPLACE(requestMessage,@old,@new) WHERE requestMessage LIKE CONCAT('%',@old,'%');

-- JSON column
UPDATE AsyncRequests SET requestMessage = CAST(REPLACE(CAST(requestMessage AS CHAR),@old,@new) AS JSON) WHERE CAST(requestMessage AS CHAR) LIKE CONCAT('%',@old,'%');
```

The same two forms apply to `ScheduledEvents.payLoad`, `FileJobs.jobParams`, `UserNotifications.data`, `ExternalModels.providerConfig`, `ConnectorJobs.args`, and `Connectors.args`.

The neural tables need care. `NeuralBatchTranslationRequests.request` holds in-flight work only and is deleted on completion, and the batch workers cache these rows in memory at startup. Prefer draining the `neural.batch.*` queues so the rows finish or fail before the cutover. If rows must be rewritten, scale the neural batch workers to zero first.

## Columns to Leave Alone

These look like paths but are not bucket URIs. Do not rewrite them.

* `Users.imageURL`: an HTTP profile picture URL from the identity provider.
* `Documents.xliff`: inline XLIFF content on legacy rows, not a path.
* `Segments.*`: `xliffFileId` and `transUnitId` are XLIFF attributes.
* `NeuralBatchTranslationJobs.request`: `dataFilePath` is a bare key with no bucket.
* Neural model storage: bare keys under `model_storage_v4/` and `trained/`; the bucket comes from configuration.
* Redis upload hand-off keys hold full URIs but live only for one request. No flush is required.

## Configuration That Must Change

After the rewrite, every location that names the bucket must say the new name. A single global value can be shadowed by a stale per-service override, so check each one in the installer values file (`lilt/values.yaml` in the on-prem installer).

* Core services: `<alias>.onpremValues.app.args.bucket` for converter, tm, job, workflow, file-job, file-translation, segment, memory, and the rest.
* file-job and job: `onpremValues.env.BUCKETNAME`.
* core-api and dataflow: `BUCKETNAME` in `env`.
* front: `front.onpremValues.config.front_configmap_values.awsS3Bucket`. This key is not present in the installer values file by default and falls back to the chart default of `lilt`, so it must be added explicitly.
* neural: `<alias>.onpremValues.config.bucket` and `init.outputPath` (`s3://<new-bucket>/trained/`).
* core chart init containers: `init.outputPath` and `filePaths` for lexicon and file-job (`s3://<new-bucket>/lexicon-data/`, `s3://<new-bucket>/tesseract/`).

Redeploy, then re-run the census. Only the new bucket prefix should remain.

## Troubleshooting

**New work downloads but anything created before the move fails**: the rewrite was skipped or ran against the wrong database. Re-run the census.

**Downloads fail for one service only**: that service still carries the old bucket in a per-service override. Compare the rendered configuration of the failing service against a working one.

**Neural reports `Wrong bucket name`**: the neural `config.bucket` or `init.outputPath` was not updated, or the neural tables still hold old URIs from work that was in flight at the cutover.
