Teixeira
Teixeira2w ago

`FST_ERR_REP_ALREADY_SENT` when using `res.send()`

I've setup context as such:
import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
import models from '../database/models.js';

interface CreateInnerContextOptions extends Partial<CreateFastifyContextOptions> {
models: typeof models;
}

export async function createInnerContext(opts: CreateInnerContextOptions) {
return {
models: opts.models
};
}

export async function createContext(fastifyOptions: CreateFastifyContextOptions) {
const innerContext = await createInnerContext({ models });

return { ...fastifyOptions, ...innerContext };
}

export type Context = Awaited<typeof createContext>;
import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
import models from '../database/models.js';

interface CreateInnerContextOptions extends Partial<CreateFastifyContextOptions> {
models: typeof models;
}

export async function createInnerContext(opts: CreateInnerContextOptions) {
return {
models: opts.models
};
}

export async function createContext(fastifyOptions: CreateFastifyContextOptions) {
const innerContext = await createInnerContext({ models });

return { ...fastifyOptions, ...innerContext };
}

export type Context = Awaited<typeof createContext>;
And a procedure like this:
import generateCampaignReport from '../../../../xlsx_reports/generateCampaignReport.js';
import { publicProcedure } from '../../../init.js';
import objectIdSchema from '../../../zod_schemas/ObjectId.js';
import { z } from 'zod';
import { Types } from 'mongoose';

export default publicProcedure
.input(
z.object({
campaignId: objectIdSchema
})
)
.mutation(async ({ input, ctx }) => {
const { campaignId } = input;
const { res } = ctx;

res.header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.header('Content-Disposition', `attachment; filename="clipx_workbook.xlsx"`);

const buffer = await generateCampaignReport(new Types.ObjectId(campaignId));
res.send(buffer);
});
import generateCampaignReport from '../../../../xlsx_reports/generateCampaignReport.js';
import { publicProcedure } from '../../../init.js';
import objectIdSchema from '../../../zod_schemas/ObjectId.js';
import { z } from 'zod';
import { Types } from 'mongoose';

export default publicProcedure
.input(
z.object({
campaignId: objectIdSchema
})
)
.mutation(async ({ input, ctx }) => {
const { campaignId } = input;
const { res } = ctx;

res.header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.header('Content-Disposition', `attachment; filename="clipx_workbook.xlsx"`);

const buffer = await generateCampaignReport(new Types.ObjectId(campaignId));
res.send(buffer);
});
Solution:
this looks like it should be an api endpoint outside of trpc
Jump to solution
4 Replies
Teixeira
TeixeiraOP2w ago
which is returning the following error:
[11:02:09.965] WARN (8548): Reply was already sent, did you forget to "return reply" in "/campaigns.generateReport?batch=1" (POST)?
reqId: "req-3"
err: {
"type": "FastifyError",
"message": "Reply was already sent, did you forget to \"return reply\" in \"/campaigns.generateReport?batch=1\" (POST)?",
"stack":
FastifyError: Reply was already sent, did you forget to "return reply" in "/campaigns.generateReport?batch=1" (POST)?
at Reply.send (C:\Users\jpedr\Documents\Workshop\Work\clipx\node_modules\fastify\lib\reply.js:132:26)
at fastifyRequestHandler (file://.../node_modules/@trpc/server/dist/adapters/fastify/fastifyRequestHandler.mjs:43:20)
at Object.<anonymous> (file://.../node_modules/@trpc/server/dist/adapters/fastify/fastifyTRPCPlugin.mjs:29:9)
"code": "FST_ERR_REP_ALREADY_SENT",
"name": "FastifyError",
"statusCode": 500
}
[11:02:09.965] WARN (8548): Reply was already sent, did you forget to "return reply" in "/campaigns.generateReport?batch=1" (POST)?
reqId: "req-3"
err: {
"type": "FastifyError",
"message": "Reply was already sent, did you forget to \"return reply\" in \"/campaigns.generateReport?batch=1\" (POST)?",
"stack":
FastifyError: Reply was already sent, did you forget to "return reply" in "/campaigns.generateReport?batch=1" (POST)?
at Reply.send (C:\Users\jpedr\Documents\Workshop\Work\clipx\node_modules\fastify\lib\reply.js:132:26)
at fastifyRequestHandler (file://.../node_modules/@trpc/server/dist/adapters/fastify/fastifyRequestHandler.mjs:43:20)
at Object.<anonymous> (file://.../node_modules/@trpc/server/dist/adapters/fastify/fastifyTRPCPlugin.mjs:29:9)
"code": "FST_ERR_REP_ALREADY_SENT",
"name": "FastifyError",
"statusCode": 500
}
as far as I am aware I can't return the Buffer directly as it would be resolved to JSON so I have to use res.send. Is there a way I can make the function not attempt to send another reply when it's returning? Using @trpc/server@11.0.0-rc.730+776d07336, fastify@5.2.1, node v22.11.0
Alex / KATT 🐱
- trpc responses are limited to json at the moment - if you're using the batch stream link, headers are sent before reaching the mutation you shouldn't access res.send() inside of a procedure
Solution
Alex / KATT 🐱
this looks like it should be an api endpoint outside of trpc
Teixeira
TeixeiraOP2w ago
Oh, that's a bummer 😦 Alright thank you very much

Did you find this page helpful?