paperclipai/paperclip · error
Invalid Teams private binding
Error message
Invalid Teams private binding
What it means
sealTeamsFileConsentBinding encrypts a TeamsFileConsentBinding into private sealed state for persistence. Before sealing it re-validates the binding against bindingSchema (parseTeamsFileConsentBinding) and requires the binding's companyId and endpointId to match the sealing context. Any mismatch or schema violation throws this error instead of sealing untrustworthy material.
Source
Thrown at server/src/services/chat-teams-file-consent.ts:166
)
throw new Error();
return envelope.value;
} catch {
throw new Error("Teams private state could not be restored");
}
}
export async function sealTeamsFileConsentBinding(
context: TeamsFilePrivateContext,
binding: TeamsFileConsentBinding,
) {
const parsed = parseTeamsFileConsentBinding(binding);
if (
!parsed ||
parsed.companyId !== context.companyId ||
parsed.endpointId !== context.endpointId
)
throw new Error("Invalid Teams private binding");
return sealPrivate(context, "binding", parsed);
}
export async function restoreTeamsFileConsentBinding(
context: TeamsFilePrivateContext,
material: TeamsFileCiphertext,
) {
const binding = parseTeamsFileConsentBinding(
await openPrivate(context, "binding", material),
);
if (
!binding ||
binding.companyId !== context.companyId ||
binding.endpointId !== context.endpointId
)
throw new Error("Invalid Teams private binding");
return binding;
}View on GitHub (pinned to 01ad858492)
Solutions
- Create the binding with createTeamsFileConsentBinding so the schema, token and freeze are applied, rather than hand-assembling the object.
- Check binding.companyId === context.companyId && binding.endpointId === context.endpointId before sealing; use the context matching the binding's origin.
- Run parseTeamsFileConsentBinding(binding) yourself and inspect the zod failure to find the offending field (e.g. token prefix, filename characters, expiresAt format).
- If migrating old data, re-create the binding through createTeamsFileConsentBinding with corrected fields (new UUIDs, ISO expiresAt) before sealing.
Example fix
// before
await sealTeamsFileConsentBinding(otherCompanyContext, binding);
// after
if (binding.companyId !== context.companyId || binding.endpointId !== context.endpointId) {
throw new Error("binding does not belong to this transfer context");
}
await sealTeamsFileConsentBinding(context, binding); Defensive patterns
Strategy: validation
Validate before calling
const parsed = parseTeamsFileConsentBinding(binding);
if (!parsed || parsed.companyId !== context.companyId || parsed.endpointId !== context.endpointId) {
throw new Error('binding invalid or scope mismatch before seal');
} Type guard
function isBindingForContext(b: unknown, ctx: TeamsFilePrivateContext): b is TeamsFileConsentBinding {
const p = parseTeamsFileConsentBinding(b);
return !!p && p.companyId === ctx.companyId && p.endpointId === ctx.endpointId;
} Try / catch
try {
const material = await sealTeamsFileConsentBinding(context, binding);
} catch (err) {
if (err instanceof Error && err.message === 'Invalid Teams private binding') {
// log binding field diffs and rebuild via createTeamsFileConsentBinding
}
} Prevention
- Always create bindings via createTeamsFileConsentBinding; never hand-assemble.
- Assert companyId/endpointId equality with the context at every call site.
- Keep bindings frozen and treat them as immutable values in transfers.
When it happens
Trigger: Calling sealTeamsFileConsentBinding with a binding that fails zod validation (missing/extra fields, non-UUID ids, bad filename, wrong token format like a non-pcfc_ token, byteSize over the 60MB cap, expiresAt not ISO datetime), or with a valid binding whose companyId/endpointId differ from context.companyId/context.endpointId.
Common situations: Constructing a binding by hand instead of via createTeamsFileConsentBinding; binding created for a different company/endpoint than the transfer context; upgrading code that added strict schema fields while old persisted objects are re-sealed; cross-tenant copy/paste of fixtures in tests.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid Discord command owner identifier
- Invalid Discord command registration scope
- Teams destination is missing its conversation identity
- Teams file destination is missing its verified route
- invalid file-card shape
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/4934e58d686be791.
Report an issue: GitHub.