Crosstalk-Solutions/project-nomad · error · InternalServerErrorException

Error parsing file: ${(error as Error).message}

Error message

Error parsing file: ${(error as Error).message}

What it means

Catch-all wrapper in DocsService.parseFile: every failure inside the method (missing filename, invalid slug, file not found, stream failure, or a Markdoc parse error from this.parse) is rethrown as InternalServerErrorException('Error parsing file: <original message>'). The original cause is only visible in the suffixed message.

Source

Thrown at admin/app/services/docs_service.ts:92

      const basePath = path.resolve(this.docsPath)
      const fullPath = path.resolve(path.join(this.docsPath, filename))
      if (!fullPath.startsWith(basePath + path.sep)) {
        throw new Error('Invalid document slug')
      }

      const fileExists = await getFileStatsIfExists(fullPath)
      if (!fileExists) {
        throw new Error(`File not found: ${filename}`)
      }

      const fileStream = await getFile(fullPath, 'stream')
      if (!fileStream) {
        throw new Error(`Failed to read file stream: ${filename}`)
      }
      const content = await streamToString(fileStream)
      return this.parse(content)
    } catch (error) {
      throw new InternalServerErrorException(`Error parsing file: ${(error as Error).message}`)
    }
  }

  private static readonly TITLE_OVERRIDES: Record<string, string> = {
    'faq': 'FAQ',
    'community-add-ons': 'Community Add-Ons',
  }

  private prettify(filename: string) {
    const slug = filename.replace(/\.md$/, '')
    if (DocsService.TITLE_OVERRIDES[slug]) {
      return DocsService.TITLE_OVERRIDES[slug]
    }
    // Remove hyphens, underscores, and file extension
    const cleaned = slug.replace(/_/g, ' ').replace(/-/g, ' ')
    // Convert to Title Case
    const titleCased = cleaned.replace(/\b\w/g, (char) => char.toUpperCase())
    return titleCased.charAt(0).toUpperCase() + titleCased.slice(1)

View on GitHub (pinned to 0bd1c6f4f9)

Solutions

  1. Parse the suffix after 'Error parsing file: ' to route to the right fix (see the specific inner errors 62-65, 61)
  2. Log the full error server-side (logger already captures it) and reproduce with the exact slug
  3. Improve the wrapper to rethrow NestJS HttpExceptions unchanged so 404/400-class causes keep their status

Example fix

// before
} catch (error) {
  throw new InternalServerErrorException(`Error parsing file: ${(error as Error).message}`)
}

// after
} catch (error) {
  if (error instanceof HttpException) throw error
  throw new InternalServerErrorException(`Error parsing file: ${(error as Error).message}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: existence + readability avoids most wrapped causes
const p = path.join(docsPath, `${slug}.md`)
if (!(await getFileStatsIfExists(p))) throw new NotFoundException(slug)

Type guard

const isDocsParseException = (e: unknown): e is InternalServerErrorException =>
  e instanceof InternalServerErrorException && e.message.startsWith('Error parsing file:')

Try / catch

try {
  const doc = await docsService.parseFile(slug)
} catch (e) {
  const cause = (e as Error).message.replace('Error parsing file: ', '')
  if (cause.startsWith('File not found')) throw new NotFoundException(cause)
  if (cause === 'Invalid document slug') throw new BadRequestException(cause)
  throw e
}

Prevention

When it happens

Trigger: Any of the inner guards firing, or parse() throwing on malformed markdown once the file content reaches it; the caller sees only this wrapper with the root cause appended after the colon.

Common situations: Debugging is slowed because 500s hide the specific cause; commonly the suffix is 'File not found', 'Invalid document slug', or 'Markdoc validation failed'.

Related errors


AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27). Data as JSON: /api/errors/4fa96b2359c73788. Report an issue: GitHub.