Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Projects missing .objectTranslation when having .fieldTranslation fail on CLI/VSCode operations #2813

Closed
evan-cm opened this issue Apr 9, 2024 · 6 comments
Labels
more information required Issue requires more information or a response from the customer stale validated Version information for this issue has been validated

Comments

@evan-cm
Copy link

evan-cm commented Apr 9, 2024

Summary

Projects created by earlier versions of the CLI do not create an empty .objectTranslation file even when there is a .fieldTranslation file. This results in modern versions of the CLI throwing an "Unexpected child metadata" error on any operation, even those not including that metadata. This means the developer is unable to do various actions, such as retrieving metadata using the org browser via VS Code. Note this includes operations that don't touch the CustomObjectTranslation.

My suggestion is twofold:

  1. Make this particular metadata type more resilient against this error
  2. Make it so less operations perform a scan that can throw this error. For instance retrieving apex classes shouldn't care what is in the object translations folder. If it does, it should warn rather than error.

Example error:
Error (1): Unexpected child metadata [/force-app/main/default/objectTranslations/Asset-en_US/asset_address.fieldTranslation-meta.xml] found for parent type [CustomObjectTranslation]

Steps To Reproduce

Creating a broken project using sfdx:

  1. Create fresh SF instance
  2. Install an older version of sfdx, I used npm to install a project specific instance of the command.
  3. On an object without an object translation, add a field translation. I used Asset.Address for my tests
  4. Create a package.xml file including CustomObjectTranslation
  5. Run the retrieve using the older version of sfdx. This is what I ran: npx sfdx force:source:retrieve -x package.xml --verbose
  6. Note that within "objectTranslations" you will see an Asset folder with only a .fieldTranslation file

Creating a broken project using updated commands:

  1. Run steps 1,3,4
  2. Run the retrieve using the up to date sf command sf project retrieve start --manifest package.xml
  3. Within objectTranslations/Asset-en_US you will see both an .objectTranslation and .fieldTranslation. Delete the .objectTranslation

Getting error with the broken project:

  • Run: sf project retrieve start --metadata ApexClass:ExampleClass
  • Go into org browser and try to retrieve any component

Expected result

Command should complete without errors. Throwing warnings make more sense in this context.

Actual result

Command throws error:
Error (1): Unexpected child metadata [/force-app/main/default/objectTranslations/Asset-en_US/asset_address.fieldTranslation-meta.xml] found for parent type [CustomObjectTranslation]

System Information

{
  "architecture": "darwin-arm64",
  "cliVersion": "@salesforce/cli/2.35.6",
  "nodeVersion": "node-v20.11.1",
  "osVersion": "Darwin 23.4.0",
  "rootPath": "/Users/<user>/.local/share/sf/client/2.35.6-3a4a215",
  "shell": "zsh",
  "pluginVersions": [
    "@oclif/plugin-autocomplete 3.0.13 (core)",
    "@oclif/plugin-commands 3.2.2 (core)",
    "@oclif/plugin-help 6.0.20 (core)",
    "@oclif/plugin-not-found 3.1.1 (core)",
    "@oclif/plugin-plugins 5.0.1 (core)",
    "@oclif/plugin-search 1.0.20 (core)",
    "@oclif/plugin-update 4.2.4 (user)",
    "@oclif/plugin-version 2.0.16 (core)",
    "@oclif/plugin-warn-if-update-available 3.0.15 (core)",
    "@oclif/plugin-which 3.1.7 (core)",
    "@salesforce/cli 2.35.6 (core)",
    "apex 3.1.0 (core)",
    "auth 3.5.0 (core)",
    "data 3.2.2 (core)",
    "deploy-retrieve 3.4.0 (core)",
    "info 3.1.0 (core)",
    "limits 3.2.0 (core)",
    "marketplace 1.1.0 (core)",
    "org 3.6.0 (core)",
    "packaging 1.26.3 (user)",
    "schema 3.2.0 (core)",
    "settings 2.1.0 (core)",
    "sobject 1.2.0 (core)",
    "source 3.2.0 (core)",
    "telemetry 3.1.17 (core)",
    "templates 56.1.0 (core)",
    "trust 3.4.0 (core)",
    "user 3.4.0 (core)"
  ]
}

Additional information

Related stories:

Doctor debug.log 1712590744871-command-debug.log

Stack trace from doctor debug log:

TypeInferenceError: Unexpected child metadata [<projectPath>/force-app/main/default/objectTranslations/Asset-en_US/asset_address.fieldTranslation-meta.xml] found for parent type [CustomObjectTranslation]
    at DecomposedSourceAdapter.populate (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/adapters/decomposedSourceAdapter.js:104:23)
    at DecomposedSourceAdapter.getComponent (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/adapters/decomposedSourceAdapter.js:69:21)
    at MetadataResolver.resolveComponent (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:125:44)
    at MetadataResolver.getComponentsFromPathRecursive (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:85:40)
    at /Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:107:63
    at Array.flatMap (<anonymous>)
    at MetadataResolver.getComponentsFromPathRecursive (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:107:43)
    at /Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:107:63
    at Array.flatMap (<anonymous>)
    at MetadataResolver.getComponentsFromPathRecursive (/Users/<user>/.local/share/sf/client/2.35.6-3a4a215/node_modules/@salesforce/source-deploy-retrieve/lib/src/resolve/metadataResolver.js:107:43)

Workaround involves deleting objectTranslations folder (works as long as you don't need to commit changes against it). This will cause git to throw a fit, so here is the workaround I found. Note you have to run this whenever changing branches:

  • cd into objectTranslations folder, run: find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd && git ls-files -z ${pwd} | xargs -0 git update-index --skip-worktree" \;
  • Delete objectTranslations
@evan-cm evan-cm added the investigating We're actively investigating this issue label Apr 9, 2024
Copy link

github-actions bot commented Apr 9, 2024

Thank you for filing this issue. We appreciate your feedback and will review the issue as soon as possible. Remember, however, that GitHub isn't a mechanism for receiving support under any agreement or SLA. If you require immediate assistance, contact Salesforce Customer Support.

@github-actions github-actions bot added the validated Version information for this issue has been validated label Apr 9, 2024
@WillieRuemmele
Copy link
Member

Hey @evan-cm - how old was the "old" version of the CLI you were using? Over the years we've had to adjust, fix, or redo how metadata was represented locally, and sometimes it's not always backwards compatible. During the transitions we've always warned and given appropriate time to adjust or prepare for a difference. If you update to the latest, as of last week, you can customize how metadata is represented locally using our Custom Decomposition.

@WillieRuemmele WillieRuemmele added more information required Issue requires more information or a response from the customer and removed investigating We're actively investigating this issue labels Apr 10, 2024
Copy link

This issue has not received a response in 7 days. It will auto-close in 7 days unless a response is posted.

@evan-cm
Copy link
Author

evan-cm commented Apr 24, 2024

@WillieRuemmele It appears the old CLI version is 7.119.2 ~3 years old. While I'm not sure the Custom Decomposition is helpful here, I appreciate you calling it out as it looks like a neat feature that I'm interested in playing with.

While I understand metadata format may change (I don't believe this is exactly what happened here), I believe my two suggestions still apply as they expand beyond this issue and helps address the general class of errors this error falls into. A project shouldn't be completely unusable because one component somewhere is malformed. Why does apex code manipulations break when an unrelated component is malformed? Warning the user on unrelated operations, and breaking on operations on that metadata makes sense to me. This would help alleviate these sorts of issues: https://github.com/forcedotcom/cli/issues?q=is%3Aissue+Unexpected+child+metadata. I also wonder about the efficiency of validating the entire package on every command, although I haven't noticed performance issues so maybe that doesn't matter.

On top of that, the error is a little confusing for the user. It feels weird that the tooling cannot infer the parent metadata from the folder name seeing as the objectTranslation file shares the name as the containing folder.

To reiterate, my two suggestions for fixes are:

  1. Update what I presume to be a project validation scan at the beginning to only warn the user if errors are found on unrelated metadata types
  2. Re-evaluate the logic for finding the parent component, do you need the objectTranslation folder, or can you get the required information from the containing folder name. Note I'd suggest a similar fix for other components that have the same sort of issues like this one.

As an aside, if anyone else is wanting to mass generate the blank objectTranslation files, this is a shell script to do so. Note that I'd still validate and ensure deploying the blank objectTranslation file does what you expect:

for brokenFile in $(diff  <(for x in force-app/main/default/objectTranslations/*/*.objectTranslation-meta.xml; do echo "$(dirname "$x")" ; done) <(printf "%s\n" force-app/main/default/objectTranslations/*) | grep ">" | sed 's!> force-app/main/default/objectTranslations/!!' )
do
    echo "Creating force-app/main/default/objectTranslations/$brokenFile/$brokenFile.objectTranslation-meta.xml"
    printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObjectTranslation></CustomObjectTranslation>\n" > force-app/main/default/objectTranslations/$brokenFile/$brokenFile.objectTranslation-meta.xml
    git add force-app/main/default/objectTranslations/$brokenFile/$brokenFile.objectTranslation-meta.xml
done

@github-actions github-actions bot removed the stale label Apr 25, 2024
@mshanemc
Copy link
Contributor

@evan-cm I've been thinking through your ideas.

Update what I presume to be a project validation scan at the beginning to only warn the user if errors are found on unrelated metadata types

it's not exactly what you're thinking (that we're doing a scan for project validation purposes). There are a few reasons we "resolve" stuff in the project before a retrieve

  1. conflict detection. If there are local changes in a file, and remote changes that map to those, we'd tell you you have conflicts and that you'd need to --ignore-conflicts so remote or local can "win".
  2. merging. We need the graph of the project so that when the retrieve happens, we can ask the question, "where do I put this?" For example, if you have an apex class called Foo in a non-default packageDir, and we retrieve a class called Foo, we need to recognize that those match and that we are updating that local Foo instead of creating a new one in the default dir.

I see your point, that for both 1 and 2, we could be more selective about what we scan (ex: we figure out what's in your retrieve flags and THEN use that information to resolve a only a subset of the local project).


As far as "why is the parent file COT required, anyway" ? Here's the metadata API docs
https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_'.htm

COFT are children of COT to the metadata API. It wants a file for the COT, and all the COFT are an array of props inside that file.

It's safer/cleaner/more deterministic to roll up the COFT files into the COT and deploy that as whole. If we were to create a COT file empty, and then add only your COFT, I'm not sure how the API interprets that. Does that mean "only update what is different (the COFT)?" or does it mean, "clear the description and gender properties from the COT? since they're not in the file anymore" [if your COT doesn't have those, and really is empty, that's one thing. But creating empty files where what's on the server might not be empty is sketchier. You'd be better off re-retrieving the COT than generating blank files via a script]


Anyone else seeing breaking changes for CO(F)T?

Copy link

github-actions bot commented May 8, 2024

This issue has not received a response in 7 days. It will auto-close in 7 days unless a response is posted.

@github-actions github-actions bot added the stale label May 8, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more information required Issue requires more information or a response from the customer stale validated Version information for this issue has been validated
Projects
None yet
Development

No branches or pull requests

3 participants