/path/to/data/foo.vrt:
<VRTDataset rasterXSize="512" rasterYSize="512">
<GeoTransform>440720.0, 60.0, 0.0, 3751320.0, 0.0, -60.0</GeoTransform>
<VRTRasterBand dataType="Byte" band="1">
<ColorInterp>Gray</ColorInterp>
<SimpleSource>
<SourceFilename relativeToVRT="1">images/utm.tif</SourceFilename>
<SourceBand>1</SourceBand>
<SrcRect xOff="0" yOff="0" xSize="512" ySize="512"/>
<DstRect xOff="0" yOff="0" xSize="512" ySize="512"/>
</SimpleSource>
</VRTRasterBand>
</VRTDataset>
So utm.tif actually exists at /path/to/data/images/utm.tif
Then symlink the .vrt
$ ls -la /path/to/projects/
lrwxrwxrwx 1 rcoup rcoup 39 Feb 12 12:55 foo.vrt -> /path/to/data/foo.vrt
If you GdalOpen() the /path/to/projects/foo.vrt, GDAL tries to resolve /path/to/projects/images/utm.tif (ie. relative to the symlink source), which fails. Because it's actually at /path/to/data/images/utm.tif (ie. relative to the symlink target).