Skip to content

rest: the record-share routes classify refusals by message.startsWith(CODE) and interpolate error.message into a hand-built 500 — a declared status/code is ignored and the sandbox wrapper reaches the client #11683

Description

@os-zhuang

Filed unassigned while implementing #11588 (the sandbox debug wrapper on the bulk write routes). Out of scope there: #11588's table names six routes and this is a third branch again, with a different defect on top of the shared one.

Measured

packages/rest/src/rest-server.ts, the record-share family — GET/POST /api/v1/data/:object/:id/shares and DELETE …/shares/:shareId. All three catches are:

}catch(error: any){if(respondSharingError(res,error))return;logError('[REST] Grant share error:',error);respondError(res,500,'SHARE_GRANT_FAILED',String(error?.message??error).slice(0,500));}

and respondSharingError is:

constmsg=String(error?.message??error??'');constmap: Array<[ErrorCode,number]>=[['VALIDATION_FAILED',400],['PERMISSION_DENIED',403],['NOT_FOUND',404],['CONFLICT',409],['SHARING_NOT_ENABLED',422],];for(const[code,status]ofmap){if(msg.startsWith(code)){respondError(res,status,code,msg.replace(...));returntrue;}}returnfalse;

Two independent problems, both on the same read of error.message:

  1. A declared status / code is ignored entirely. These routes touch neither classifyDataError's unwrap door nor resolveErrorResponse's declared-status passthrough. A producer that throws Object.assign(new Error(msg), { code: 'RECORD_LOCKED', status: 409 }) — the ADR-0112 envelope every other /data face honours — is answered 500 SHARE_GRANT_FAILED, because 'RECORD_LOCKED' is not one of the five prefixes. This is the same "classification is a property of the message's wording" shape analytics 的 filter 拒收到不了调用方:service 侧多数拒收没有 ADR-0112 信封,REST 面又用 message 正则嗅探,一律答 500 #5352/analytics dataset 路由的 message 正则兜底没有退休时间表:六族拒收仍靠措辞分类,改一个字就换一个 HTTP 码 #5367 paid off on /analytics/dataset/query, still standing here.

  2. The sandbox debug wrapper reaches the client, which is rest: the sandbox debug wrapper hook '<name>' threw: Error: … reaches the client on every write route that exits above mapDataError's unwrap (batch, createMany, updateMany, deleteMany, clone, analytics) #11588's defect on a branch rest: the sandbox debug wrapper hook '<name>' threw: Error: … reaches the client on every write route that exits above mapDataError's unwrap (batch, createMany, updateMany, deleteMany, clone, analytics) #11588 did not fix. A sandboxed hook refusal arrives with .message = hook '<name>' threw: Error: <business text> and .innerMessage = the business text. msg.startsWith(CODE) never matches (the wrapper is the prefix), so it falls to the 500 arm and the wrapper is interpolated verbatim.

Why it was not fixed in #11588

#11588's dispatch fenced the card to the six routes its table measured, and this family is not among them. It is also a larger repair than the message read: the right answer is almost certainly to route these three catches through handleRouteError like every other /data route, which changes their status/code answers, not just their prose — a behaviour change that deserves its own card and its own pins.

Not established here

Region: packages/rest/src/rest-server.ts, respondSharingError and the three share-route catches only.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions