{"record":{"id":"ba69d7df4a8ac82e","repo":"wavetermdev/waveterm","slug":"blockid-is-required","errorCode":null,"errorMessage":"blockid is required","messagePattern":"blockid is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshserver/wshserver.go","lineNumber":838,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing blockfiles: %w\", err)\n\t}\n\tvar fileInfoList []*wshrpc.WaveFileInfo\n\tfor _, wf := range fileList {\n\t\tfileInfoList = append(fileInfoList, waveFileToWaveFileInfo(wf))\n\t}\n\treturn &wshrpc.BlockInfoData{\n\t\tBlockId:     blockId,\n\t\tTabId:       tabId,\n\t\tWorkspaceId: workspaceId,\n\t\tBlock:       blockData,\n\t\tFiles:       fileInfoList,\n\t}, nil\n}\n\nfunc (ws *WshServer) DebugTermCommand(ctx context.Context, data wshrpc.CommandDebugTermData) (*wshrpc.CommandDebugTermRtnData, error) {\n\tif data.BlockId == \"\" {\n\t\treturn nil, fmt.Errorf(\"blockid is required\")\n\t}\n\tif data.Size <= 0 {\n\t\treturn nil, fmt.Errorf(\"size must be greater than 0\")\n\t}\n\twaveFile, err := filestore.WFS.Stat(ctx, data.BlockId, wavebase.BlockFile_Term)\n\tif err == fs.ErrNotExist {\n\t\treturn &wshrpc.CommandDebugTermRtnData{}, nil\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error statting term file: %w\", err)\n\t}\n\treadSize := data.Size\n\tdataLength := waveFile.DataLength()\n\tif readSize > dataLength {\n\t\treadSize = dataLength\n\t}\n\treadOffset := waveFile.Size - readSize\n\treadOffset, readData, err := filestore.WFS.ReadAt(ctx, data.BlockId, wavebase.BlockFile_Term, readOffset, readSize)","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshserver/wshserver.go#L820-L856","documentation":"DebugTermCommand dumps the tail of a block's terminal debug file via WFS. It rejects the call up front when the required BlockId field of CommandDebugTermData is empty, since it cannot locate the term file without it.","triggerScenarios":"Calling wsh rpc DebugTermCommand with a CommandDebugTermData where BlockId is \"\" (zero value, never set).","commonSituations":"Scripts building the RPC payload programmatically and forgetting to fill BlockId; callers using a default-constructed struct; deserialization dropping the field when the client omits it in JSON.","solutions":["Set CommandDebugTermData.BlockId to the target block's OID before invoking the RPC","Verify the block exists (wsh blocks list or wstore lookup) and copy its ID into the request","Check that the client-side JSON payload actually serializes blockid (field not accidentally empty)"],"exampleFix":"// before\nresp, err := client.DebugTermCommand(ctx, wshrpc.CommandDebugTermData{Size: 1024})\n// after\nresp, err := client.DebugTermCommand(ctx, wshrpc.CommandDebugTermData{BlockId: blockId, Size: 1024})","handlingStrategy":"validation","validationCode":"if data.BlockId == \"\" {\n    return fmt.Errorf(\"cannot call DebugTermCommand: BlockId is empty\")\n}","typeGuard":"func hasBlockId(data wshrpc.CommandDebugTermData) bool {\n    return data.BlockId != \"\"\n}","tryCatchPattern":"resp, err := client.DebugTermCommand(ctx, data)\nif err != nil {\n    if strings.Contains(err.Error(), \"blockid is required\") {\n        // fix payload: set BlockId\n    }\n    return err\n}","preventionTips":["Always obtain BlockId from a block lookup/list before calling","Validate required RPC fields at the client boundary","Use constructor helpers that require BlockId"],"tags":["validation","rpc","wsh","missing-parameter"],"backgroundTag":"missing-required-argument","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}