Stack Debugging
用于排查 @outfitter/* 包的问题。
Result 问题
总是得到 Error
症状:Result 本应为 ok 却变成 err。
检查校验:
const inputResult = validateInput(rawInput);
if (inputResult.isErr()) {
console.log("Validation failed:", inputResult.error.details);
return inputResult;
}
检查异步:
// BAD: Missing await
const result = getUser(id); // Promise, not Result!
// GOOD
const result = await getUser(id);
类型收窄失效
症状:在 isOk() 之后 TypeScript 无法识别类型。
// BAD: Reassigning breaks narrowing
let result = await getUser(id);
if (result.isOk()) {
result = await updateUser(result.value); // Breaks!
}
// GOOD: Separate variables
const getResult = await getUser(id);
if (getResult.isErr()) return getResult;
const updateResult = await updateUser(getResult.value);
错误类型丢失
使用 _tag 进行收窄:
if (result.isErr()) {
switch (result.error._tag) {
case "ValidationError":
console.log(result.error.details);
break;
case "NotFoundError":
console.log(result.error.resourceId);
break;
}
}
MCP 问题
工具不出现
在 start() 之前注册:
server.registerTool(myTool);
server.start(); // After registration!
检查 schema 是有效的 Zod 且带 .describe():
const schema = z.object({
query: z.string().describe("Required for AI"),
});
工具调用失败
确认 handler 是异步的:
handler: async (input) => { // Not sync!
return Result.ok(data);
}
返回 Result,而不是原始值:
// BAD
return { data: "value" };
// GOOD
return Result.ok({ data: "value" });
CLI 输出问题
JSON 未打印
强制模式:
await output(data, { mode: "json" });
检查环境:
OUTFITTER_JSON=1 myapp list
OUTFITTER_JSON=0 myapp list --json # Forces human!
等待 output:
// BAD
output(data);
process.exit(0); // May exit before output!
// GOOD
await output(data);
退出码错误
使用 exitWithError:
// BAD
process.exit(1);
// GOOD
exitWithError(result.error);
退出码表:
| Category | Exit |
|---|---|
| validation | 1 |
| not_found | 2 |
| conflict | 3 |
| permission | 4 |
| timeout | 5 |
| rate_limit | 6 |
| network | 7 |
| internal | 8 |
| auth | 9 |
| cancelled | 130 |
日志问题
Redaction 不生效
const logger = createLogger({
redaction: { enabled: true }, // Must be true!
});
// Custom patterns
const logger = createLogger({
redaction: {
enabled: true,
patterns: ["password", "apiKey", "myCustomSecret"],
},
});
缺少上下文
import { createChildLogger } from "@outfitter/logging";
const requestLogger = createChildLogger(ctx.logger, {
requestId: ctx.requestId,
handler: "myHandler",
});
requestLogger.info("Processing", { data }); // Includes requestId
级别错误
const logger = createLogger({
level: process.env.LOG_LEVEL || "info",
});
// Hierarchy: trace < debug < info < warn < error < fatal
// "info" hides trace and debug
调试工具
追踪 Result 链
function traceResult<T, E>(name: string, result: Result<T, E>): Result<T, E> {
console.log(`[${name}]`, result.isOk() ? "OK:" : "ERR:",
result.isOk() ? result.value : result.error);
return result;
}
const result = traceResult("getUser", await getUser(id));
检查 Context
console.log("Context:", {
requestId: ctx.requestId,
hasLogger: !!ctx.logger,
hasConfig: !!ctx.config,
hasSignal: !!ctx.signal,
cwd: ctx.cwd,
});
校验 Zod Schema
const parseResult = schema.safeParse(rawInput);
if (!parseResult.success) {
console.log("Zod errors:", parseResult.error.issues);
}
相关技能
- outfitter-stack:stack-patterns — 正确模式
- outfitter-stack:stack-review — 系统化审计