paperclipai/paperclip · error · ValidationError

VALIDATION_ERROR

VALIDATION_ERROR

Error message

Invalid durable publication text transport

What it means

renderPublicationTransportText/rendered/splitNativePublicationText only accept persisted publication text that matches a strict fenced-wrapper grammar (PREFIX/SUFFIX regexes on a ``` or ~~~ fence with an optional short extension tag). invalidTransport throws a ValidationError with code VALIDATION_ERROR when the stored text cannot be parsed as such a wrapper, so arbitrary persisted prose, links, or credentials are never treated as a transport envelope.

Source

Thrown at server/src/services/chat-publication-text-parts.ts:25

} from "chat";
import type { SafeChatPublicationPayload } from "@paperclipai/shared";

type NativeTextProvider = "slack" | "github" | "microsoft-teams";
export interface NativePublicationTextPart {
  text: string;
  prefix?: string;
  suffix?: string;
}
const slack = new SlackFormatConverter();
const teams = new TeamsFormatConverter();
const MAX_WRAPPER_LENGTH = 292;
const PREFIX = /^(`{3,256}|~{3,256})([A-Za-z0-9_+.-]{0,32})\n$/;
const SUFFIX = /^\n(`{3,256}|~{3,256})\n?$/;

function invalidTransport(): never {
  throw Object.assign(new Error("Invalid durable publication text transport"), {
    name: "ValidationError",
    code: "VALIDATION_ERROR",
  });
}

/** Never accept arbitrary persisted prose, links, or credentials as a wrapper. */
export function renderPublicationTransportText(
  payload: SafeChatPublicationPayload,
): string {
  const part = payload.transportPart;
  const prefix: unknown = part?.prefix;
  const suffix: unknown = part?.suffix;
  if (prefix === undefined && suffix === undefined) return payload.text;
  if (part?.mode && part.mode !== "inline") invalidTransport();
  if (
    prefix !== undefined &&
    (typeof prefix !== "string" ||
      prefix.length > MAX_WRAPPER_LENGTH ||
      !PREFIX.test(prefix))
  )

View on GitHub (pinned to 01ad858492)

Solutions

  1. Rewrite the persisted publication text so it is a complete fenced wrapper: open fence line (3-256 backticks/tildes plus optional tag + newline), payload, then closing fence line.
  2. Use splitNativePublicationText/renderPublicationTransportText to regenerate the envelope from the payload instead of hand-authoring the stored text.
  3. If the row is legacy/unfenced, re-publish the payload through the normal publication path so a valid transport text is written.
  4. Verify the fence tag is only [A-Za-z0-9_+.-] and <=32 chars and the fence is <=256 marks; anything else is rejected.

Example fix

// before (stored text)
"some plain publication prose\n"
// after
"```json\n{\"title\":\"...\"}\n```\n"
Defensive patterns

Strategy: try-catch

Validate before calling

const PREFIX = /^(`{3,256}|~{3,256})([A-Za-z0-9_+.-]{0,32})\n$/;
if (!PREFIX.test(firstLine) || !/^\n(`{3,256}|~{3,256})\n?$/.test(tail)) throw new Error("not a valid publication transport");

Type guard

function isPublicationTransport(text: string): boolean {
  return text.startsWith("```") || text.startsWith("~~~");
}

Try / catch

try {
  const parts = splitNativePublicationText(stored);
} catch (e) {
  if ((e as { code?: string }).code === "VALIDATION_ERROR") {
    // re-publish payload through renderPublicationTransportText to rebuild a valid envelope
  }
}

Prevention

When it happens

Trigger: Calling renderPublicationTransportText(payload), rendered(), or splitNativePublicationText() with a SafeChatPublicationPayload whose text does not end with a fence line matching /^(`{3,256}|~{3,256})([A-Za-z0-9_+.-]{0,32})\n$/ and close with the matching SUFFIX fence.

Common situations: A row in the DB was written by hand or by an older code path without the fenced transport wrapper; a migration or manual edit mangled the fence line (wrong backtick count, trailing spaces, missing newline after the fence); someone pasted plain markdown into the publication field.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/0b7de0ec8ad204e0. Report an issue: GitHub.