hcengineering/platform · error · ApiError

File ${file} not found

Error message

File ${file} not found

What it means

The /convert/:file endpoint first checks that the requested file exists in the workspace's storage via storageAdapter.stat. If no object with that name exists, the endpoint throws this 404 ApiError. Conversion never runs on missing files.

Source

Thrown at services/print/pod-print/src/server.ts:251

      const printId = `print-${generateId()}`

      await storageAdapter.put(ctx, wsIds, printId, printRes, `application/${options.kind}`, printRes.length)

      res.contentType('application/json')
      res.send({ id: printId })
    })
  )

  app.get(
    '/convert/:file',
    wrapRequest(async (req, res, wsUuid) => {
      const convertableFormats = ['application/vnd.openxmlformats-officedocument.wordprocessingml.document']
      const ctx = req.ctx
      const file = req.params.file
      const stat = await storageAdapter.stat(ctx, wsUuid, file)

      if (stat === undefined) {
        throw new ApiError(404, `File ${file} not found`)
      }

      if (!convertableFormats.includes(stat.contentType)) {
        throw new ApiError(400, `File of this type (${stat.contentType}) cannot be converted`)
      }

      const convertId = getConvertId(file, stat.etag)
      const convertStats = await storageAdapter.stat(ctx, wsUuid, convertId)

      if (convertStats === undefined) {
        const originalFile = await storageAdapter.read(ctx, wsUuid, file)

        if (originalFile === undefined) {
          throw new ApiError(404, `File ${file} not found`)
        }

        const htmlRes = await ctx.with('convertToHtml', {}, () => convertToHtml(Buffer.concat(originalFile as any)))

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Verify the file identifier is the exact storage key used at upload time (from storageAdapter.put / upload response).
  2. Confirm the request token resolves to the same workspace the file was uploaded to.
  3. Re-upload the file if it was deleted, then convert.
  4. List/stat the object first to confirm existence before calling convert.

Example fix

// before
await fetch(`/convert/${displayName}.docx`, { headers })
// after
const stat = await fetch(`${storageUrl}/${fileKey}`, { method: 'HEAD', headers })
if (stat.ok) await fetch(`/convert/${encodeURIComponent(fileKey)}`, { headers })
Defensive patterns

Strategy: validation

Validate before calling

async function assertFileExists (fileKey: string, headers: HeadersInit): Promise<void> {
  const res = await fetch(`/convert/${encodeURIComponent(fileKey)}`, { method: 'HEAD', headers })
  // Endpoint itself 404s; verify via your own upload registry instead:
  if (!uploadedKeys.has(fileKey)) throw new Error(`File key not uploaded to this workspace: ${fileKey}`)
}

Try / catch

try {
  const res = await fetch(`/convert/${encodeURIComponent(fileKey)}`, { headers })
  if (res.status === 404) {
    const body = await res.json()
    throw new Error(`File missing in workspace storage: ${body.message}`)
  }
  return await res.json()
} catch (err) { /* handle: re-upload or surface to user */ }

Prevention

When it happens

Trigger: GET /convert/:file where the file key doesn't exist in the workspace storage — wrong file name/UUID, file uploaded to a different workspace, or file already deleted/purged from the storage adapter.

Common situations: Client caching file names after the document was deleted; using a display filename instead of the storage key; cross-workspace token used against another workspace's files; typos in the path parameter.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/a42333fa1b3d3b68. Report an issue: GitHub.