nexu-io/open-design · error · DeployError

Could not deploy referenced files (${parts.join('; ')}).

Error message

Could not deploy referenced files (${parts.join('; ')}).

What it means

Thrown by buildDeployFileSet in apps/daemon/src/deploy.ts:349 as `DeployError('Could not deploy referenced files (...).', 400, { missing, invalid })`. buildDeployFileSet calls buildDeployFilePlan and, unlike the plan step (which intentionally returns missing/invalid without throwing), refuses to produce an uploadable file set when the entry HTML references assets that are missing on disk or resolve to invalid (out-of-scope/blocked) paths. The interpolated parts list distinguishes `missing:` and `invalid:` references, and the details object carries the raw arrays.

Source

Thrown at apps/daemon/src/deploy.ts:349

    });
  }

  return {
    entryPath,
    html,
    files: Array.from(files.values()),
    missing,
    invalid,
  };
}

export async function buildDeployFileSet(projectsRoot: string, projectId: string, entryName: string, options: DeployOptions = {}) {
  const plan = await buildDeployFilePlan(projectsRoot, projectId, entryName, options);
  if (plan.missing.length || plan.invalid.length) {
    const parts = [];
    if (plan.missing.length) parts.push(`missing: ${plan.missing.join(', ')}`);
    if (plan.invalid.length) parts.push(`invalid: ${plan.invalid.join(', ')}`);
    throw new DeployError(`Could not deploy referenced files (${parts.join('; ')}).`, 400, {
      missing: plan.missing,
      invalid: plan.invalid,
    });
  }
  return plan.files;
}

async function addVisibleProjectFilesToDeployPlan(
  files: Map<string, DeployFile>,
  input: { projectsRoot: string; projectId: string; metadata?: unknown },
) {
  if (isLinkedFolderProject(input.metadata)) return;
  const projectFiles = await listFiles(input.projectsRoot, input.projectId, { metadata: input.metadata });
  for (const item of projectFiles) {
    if (!item?.name || files.has(item.name)) continue;
    const safePath = validateProjectPath(item.name);
    // The selected entry is already mapped to provider-root index.html. Keep
    // the original root index reserved so choosing index-v1.html does not get

View on GitHub (pinned to 5be4028344)

Solutions

  1. Inspect the returned `details.missing` and `details.invalid` arrays to get the exact broken references.
  2. Restore or re-export the missing assets so every reference in the entry HTML resolves under the project directory.
  3. Rewrite references that escape the project (remove leading `/` or `../`) so they resolve relative to the entry.
  4. If using a linked folder project, ensure referenced files live under `metadata.baseDir`.

Example fix

// before
<!-- index.html -->
<link rel="stylesheet" href="/assets/style.css"> <!-- missing/invalid -->

// after
<link rel="stylesheet" href="assets/style.css"> <!-- relative, exists in project -->
Defensive patterns

Strategy: validation

Validate before calling

// Call the non-throwing plan first, surface missing/invalid to the user.
const plan = await buildDeployFilePlan(root, id, entryName, opts);
if (plan.missing.length || plan.invalid.length) {
  return res.status(400).json({
    error: 'Fix referenced files before deploying.',
    missing: plan.missing,
    invalid: plan.invalid,
  });
}
const files = await buildDeployFileSet(root, id, entryName, opts);

Type guard

function hasReferenceIssues(plan: DeployFilePlan): boolean {
  return plan.missing.length > 0 || plan.invalid.length > 0;
}

Try / catch

try {
  files = await buildDeployFileSet(root, id, entryName, opts);
} catch (err) {
  if (err instanceof DeployError && err.details && (err.details.missing || err.details.invalid)) {
    return res.status(400).json({
      error: err.message,
      missing: err.details.missing,
      invalid: err.details.invalid,
    });
  }
  throw err;
}

Prevention

When it happens

Trigger: The entry HTML's `<link>`, `<script src>`, `<img src>`, or other references point to files that don't exist in the project (populating `plan.missing`) or that `validateProjectPath` rejects as outside the sandbox / otherwise invalid (populating `plan.invalid`), and buildDeployFileSet is then called.

Common situations: Assets were deleted or moved after the HTML was generated; absolute or `../` references that escape the project directory; references to files filtered out by the deploy file allowlist; case-sensitivity mismatch on a case-sensitive filesystem; linked folder project referencing external paths.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/d6f004f39a15475d. Report an issue: GitHub.