Answers.Body: <p>Not an answer directly to your question but a general function to upload an asset in PHP. In my case <code>$file</code> is an uploaded file in the <code>$_FILES</code> array. You can <a href="https://stackoverflow.com/questions/3938534/download-file-to-server-from-url">download a file per url</a> and insert it's <code>tmp_name</code> and <code>name</code> manually</p>
  
  <pre><code>/**
   * Upload a file
   *
   * @param $file
   * @return int|null|string
   * @throws \Throwable
   * @throws \craft\errors\ElementNotFoundException
   * @throws \yii\base\Exception
   */
  public function uploadImage($file)
  {
      $assets = Craft::$app-&gt;getAssets();
      $folderId = 1; //&lt;- insert your folder id
  
      /** @var \craft\models\VolumeFolder $folder */
      $folder = $assets-&gt;findFolder(['id' =&gt; $folderId]);
  
      $asset = new Asset();
      $asset-&gt;tempFilePath = $file['tmp_name'];
      $asset-&gt;filename = $file['name'];
      $asset-&gt;newFolderId = $folder-&gt;id;
      $asset-&gt;volumeId = $folder-&gt;volumeId;
      $asset-&gt;avoidFilenameConflicts = true;
      $asset-&gt;setScenario(Asset::SCENARIO_CREATE);
  
      $result = Craft::$app-&gt;getElements()-&gt;saveElement($asset);
  
      // In case of error, let user know about it.
      if ($result === false) {
          throw new Exception('Error while upload asset');
      }
  
      return $asset-&gt;id;
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-03-27T11:43:14.727Z
Answers.LastActivityDate: 2018-03-27T11:43:14.727Z
Answers.UserDisplayName: Robin Schambach
Answers.Body: <p>I ran into this problem too, and isolated it to AssetLocationValidator.php on line 110 or so.  </p>
  
  <pre><code>// If nothing has changed, just null-out the newLocation attribute
  if (!$hasNewFolderId &amp;&amp; !$hasNewFilename) {
      $model-&gt;$attribute = null;
  
      return;
  }
  </code></pre>
  
  <p>but the problem is, having a null newLocation throws a validation error.</p>
  
  <p>My solution was to set the folderId as 0, and the newFolderId as the destination folder.  This keeps the "null out the newLocation..." from firing, and keeps the newLocation populated.</p>
  
  <pre><code>$asset = new Asset();
  $asset-&gt;tempFilePath = $tempPath;
  $asset-&gt;filename = $filename;
  $asset-&gt;folderId = 0;
  $asset-&gt;newFolderId = $folder-&gt;id;
  $asset-&gt;volumeId = $folder-&gt;volumeId;
  $asset-&gt;avoidFilenameConflicts = true;
  $asset-&gt;setScenario(Asset::SCENARIO_CREATE);
  
  $result = Craft::$app-&gt;getElements()-&gt;saveElement($asset);
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-07-02T17:53:29.263Z
Answers.LastActivityDate: 2018-07-02T17:53:29.263Z
Answers.UserDisplayName: Mark Middleton
Body: <p>I'm working on a plugin in Craft 3 that is fetching a file reference (URL) via an API.</p>
  
  <p>I want to fetch the file and save it locally as an Asset. I've tried to do this via <code>Craft::$app-&gt;getElements()-&gt;saveElement()</code> but am getting the following error:</p>
  
  <p><code>New Location cannot be blank.</code></p>
  
  <p>Any thoughts on this issue or where to dig a bit deeper to resolve?</p>
  
  <p>Cole </p>
  
Tags: <plugin-development><assets><craft3><plugin-elementapi>
Title: Saving asset programatically, eg via API
ThreadText: # Saving asset programatically, eg via API
  
  (Asked by: username_0 on 2018-03-27)
  
  I'm working on a plugin in Craft 3 that is fetching a file reference (URL) via an API.
  
  I want to fetch the file and save it locally as an Asset. I've tried to do this via `Craft::$app->getElements()->saveElement()` but am getting the following error:
  
  `New Location cannot be blank.`
  
  Any thoughts on this issue or where to dig a bit deeper to resolve?
  
  username_0
  
  **Tags:** plugin-development, assets, craft3, plugin-elementapi
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2018-03-27. Score: 4
  
  Not an answer directly to your question but a general function to upload an asset in PHP. In my case `$file` is an uploaded file in the `$_FILES` array. You can [download a file per url](https://stackoverflow.com/questions/3938534/download-file-to-server-from-url) and insert it's `tmp_name` and `name` manually
  
  ```
  /**
   * Upload a file
   *
   * @param $file
   * @return int|null|string
   * @throws \Throwable
   * @throws \craft\errors\ElementNotFoundException
   * @throws \yii\base\Exception
   */
  public function uploadImage($file)
  {
      $assets = Craft::$app->getAssets();
      $folderId = 1; //<- insert your folder id
  
      /** @var \craft\models\VolumeFolder $folder */
      $folder = $assets->findFolder(['id' => $folderId]);
  
      $asset = new Asset();
      $asset->tempFilePath = $file['tmp_name'];
      $asset->filename = $file['name'];
      $asset->newFolderId = $folder->id;
      $asset->volumeId = $folder->volumeId;
      $asset->avoidFilenameConflicts = true;
      $asset->setScenario(Asset::SCENARIO_CREATE);
  
      $result = Craft::$app->getElements()->saveElement($asset);
  
      // In case of error, let user know about it.
      if ($result === false) {
          throw new Exception('Error while upload asset');
      }
  
      return $asset->id;
  }
  
  ```
  
  
  ---
  
  ### Answer by username_2 on 2018-07-02. Score: 1
  
  I ran into this problem too, and isolated it to AssetLocationValidator.php on line 110 or so.
  
  ```
  // If nothing has changed, just null-out the newLocation attribute
  if (!$hasNewFolderId && !$hasNewFilename) {
      $model->$attribute = null;
  
      return;
  }
  
  ```
  
  but the problem is, having a null newLocation throws a validation error.
  
  My solution was to set the folderId as 0, and the newFolderId as the destination folder. This keeps the "null out the newLocation..." from firing, and keeps the newLocation populated.
  
  ```
  $asset = new Asset();
  $asset->tempFilePath = $tempPath;
  $asset->filename = $filename;
  $asset->folderId = 0;
  $asset->newFolderId = $folder->id;
  $asset->volumeId = $folder->volumeId;
  $asset->avoidFilenameConflicts = true;
  $asset->setScenario(Asset::SCENARIO_CREATE);
  
  $result = Craft::$app->getElements()->saveElement($asset);
  
  ```
  
  
  ---
  
  