nexu-io/open-design · error · ArtifactManifestRequiredError

ARTIFACT_MANIFEST_REQUIRED

ARTIFACT_MANIFEST_REQUIRED

Error message

artifactManifest is required for ${name}; no safe default manifest can be inferred

What it means

Thrown by resolveCreateArtifactManifest() as ArtifactManifestRequiredError (code ARTIFACT_MANIFEST_REQUIRED) when no artifactManifest was supplied AND inferLegacyManifest() could not infer one from the file extension. Legacy inference only covers .html/.htm (html or deck), .md (markdown-document), and .svg (svg). Any other extension without an explicit manifest hits this.

Source

Thrown at apps/daemon/src/artifacts/create.ts:66

    encoding: input.encoding === 'base64' ? 'base64' : 'utf8',
    artifact: true,
    overwrite: false,
    ...(input.artifactManifest === undefined ? {} : { artifactManifest: input.artifactManifest }),
  };
}

export function resolveCreateArtifactManifest(input: CreateProjectArtifactInput): unknown {
  const manifest = input.artifactManifest !== undefined && input.artifactManifest !== null
    ? input.artifactManifest
    : inferLegacyManifest(input.name);
  if (manifest) {
    const validated = validateArtifactManifestInput(manifest, input.name);
    if (!validated.ok) {
      throw new ArtifactManifestInvalidError(validated.error);
    }
    return validated.value;
  }
  throw new ArtifactManifestRequiredError(input.name);
}

export async function createProjectArtifactFile(options: CreateProjectArtifactOptions): Promise<unknown> {
  const { input } = options;
  const body = input.encoding === 'base64'
    ? Buffer.from(input.content, 'base64')
    : Buffer.from(input.content, 'utf8');
  return await options.writeProjectFile(
    options.projectsRoot,
    options.projectId,
    input.name,
    body,
    {
      overwrite: false,
      artifactManifest: resolveCreateArtifactManifest(input),
    },
    options.metadata,
  );

View on GitHub (pinned to 5be4028344)

Solutions

  1. Provide an explicit artifactManifest in the request body (or via --manifest for the CLI).
  2. Rename the file to .html/.htm/.md/.svg if you genuinely want the inferred manifest.
  3. For react-component/mini-app/diagram/code-snippet/design-system kinds, always supply the manifest — inference does not cover them.

Example fix

// before
await postCreateArtifactRequest({
  baseUrl, projectId,
  input: { name: 'widget.tsx', content, encoding: 'utf8' }
});
// after — explicit manifest for a react-component
await postCreateArtifactRequest({
  baseUrl, projectId,
  input: {
    name: 'widget.tsx', content, encoding: 'utf8',
    artifactManifest: {
      kind: 'react-component',
      renderer: 'react-component',
      exports: ['jsx', 'zip']
    }
  }
});
Defensive patterns

Strategy: validation

Validate before calling

import { inferLegacyManifest } from './artifacts/manifest.js';
const needsExplicit = !inferLegacyManifest(name); // null for non-html/md/svg
if (needsExplicit && !artifactManifest) {
  throw new Error(`an explicit artifactManifest is required for ${name}`);
}

Type guard

const INFERABLE_EXT = new Set(['.html', '.htm', '.md', '.svg']);
function inferableFromName(name: string): boolean {
  return INFERABLE_EXT.has(name.slice(name.lastIndexOf('.')).toLowerCase());
}

Try / catch

try {
  resolveCreateArtifactManifest(input);
} catch (e) {
  if (e instanceof ArtifactManifestRequiredError) {
    // prompt user for a manifest, then retry
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /api/projects/:id/files with artifact=true for a file whose name ends in something other than .html/.htm/.md/.svg (e.g. .json, .tsx, .png, no extension) and no artifactManifest in the body. Same path via `od artifacts create --name foo.json` without --manifest.

Common situations: Creating a react-component / mini-app / diagram / code-snippet / design-system artifact (none of which are inferable) and forgetting the manifest; renaming a file to a custom extension; creating an artifact with no extension.

Related errors


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